refreshed settings UI (fixes #314)

This commit is contained in:
Eugene Pankov
2018-04-01 19:51:04 +02:00
parent 9a8bad4851
commit 5087224017
11 changed files with 376 additions and 258 deletions

View File

@@ -0,0 +1,4 @@
.icon((click)='click()', tabindex='0', [class.active]='model', (keyup.space)='click()')
i.fa.fa-square-o.off
i.fa.fa-check-square.on
.text((click)='click()') {{text}}

View File

@@ -0,0 +1,51 @@
:host {
cursor: pointer;
margin: 5px 0;
&:focus {
background: rgba(255,255,255,.05);
border-radius: 5px;
}
&:active {
background: rgba(255,255,255,.1);
border-radius: 3px;
}
&[disabled] {
opacity: 0.5;
}
display: flex;
flex-direction: row;
align-items: center;
.icon {
position: relative;
flex: none;
width: 14px;
height: 14px;
i {
position: absolute;
left: 0;
top: -2px;
transition: 0.25s opacity;
display: block;
font-size: 18px;
}
i.on, &.active i.off {
opacity: 0;
}
i.off, &.active i.on {
opacity: 1;
}
}
.text {
flex: auto;
margin-left: 8px;
}
}

View File

@@ -0,0 +1,45 @@
import { NgZone, Component, Input } from '@angular/core'
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'
@Component({
selector: 'checkbox',
template: require('./checkbox.component.pug'),
styles: [require('./checkbox.component.scss')],
providers: [
{ provide: NG_VALUE_ACCESSOR, useExisting: CheckboxComponent, multi: true },
]
})
export class CheckboxComponent implements ControlValueAccessor {
@Input() model: boolean
@Input() disabled: boolean
@Input() text: string
private changed = new Array<(val: boolean) => void>()
click () {
NgZone.assertInAngularZone()
if (this.disabled) {
return
}
this.model = !this.model
for (let fx of this.changed) {
fx(this.model)
}
}
writeValue (obj: any) {
this.model = obj
}
registerOnChange (fn: any): void {
this.changed.push(fn)
}
registerOnTouched (fn: any): void {
this.changed.push(fn)
}
setDisabledState (isDisabled: boolean) {
this.disabled = isDisabled
}
}

View File

@@ -18,6 +18,7 @@ import { TouchbarService } from './services/touchbar.service'
import { UpdaterService } from './services/updater.service' import { UpdaterService } from './services/updater.service'
import { AppRootComponent } from './components/appRoot.component' import { AppRootComponent } from './components/appRoot.component'
import { CheckboxComponent } from './components/checkbox.component'
import { TabBodyComponent } from './components/tabBody.component' import { TabBodyComponent } from './components/tabBody.component'
import { SafeModeModalComponent } from './components/safeModeModal.component' import { SafeModeModalComponent } from './components/safeModeModal.component'
import { StartPageComponent } from './components/startPage.component' import { StartPageComponent } from './components/startPage.component'
@@ -65,6 +66,7 @@ const PROVIDERS = [
], ],
declarations: [ declarations: [
AppRootComponent, AppRootComponent,
CheckboxComponent,
StartPageComponent, StartPageComponent,
TabBodyComponent, TabBodyComponent,
TabHeaderComponent, TabHeaderComponent,
@@ -76,6 +78,9 @@ const PROVIDERS = [
entryComponents: [ entryComponents: [
RenameTabModalComponent, RenameTabModalComponent,
SafeModeModalComponent, SafeModeModalComponent,
],
exports: [
CheckboxComponent
] ]
}) })
export default class AppModule { export default class AppModule {

View File

@@ -47,6 +47,7 @@ $input-color-placeholder: #333;
$input-border-color: #344; $input-border-color: #344;
//$input-box-shadow: inset 0 1px 1px rgba($black,.075); //$input-box-shadow: inset 0 1px 1px rgba($black,.075);
$input-border-radius: 0; $input-border-radius: 0;
$custom-select-border-radius: 0;
$input-bg-focus: $input-bg; $input-bg-focus: $input-bg;
//$input-border-focus: lighten($brand-primary, 25%); //$input-border-focus: lighten($brand-primary, 25%);
//$input-box-shadow-focus: $input-box-shadow, rgba($input-border-focus, .6); //$input-box-shadow-focus: $input-box-shadow, rgba($input-border-focus, .6);
@@ -83,6 +84,8 @@ $alert-danger-bg: $body-bg2;
$alert-danger-text: $red; $alert-danger-text: $red;
$alert-danger-border: $red; $alert-danger-border: $red;
$headings-font-weight: lighter;
$headings-color: #eee;
@import '~bootstrap/scss/bootstrap.scss'; @import '~bootstrap/scss/bootstrap.scss';
@@ -147,6 +150,7 @@ app-root {
} }
&.active { &.active {
color: white;
background: $body-bg; background: $body-bg;
border-left: 1px solid $border-color; border-left: 1px solid $border-color;
border-right: 1px solid $border-color; border-right: 1px solid $border-color;
@@ -328,3 +332,15 @@ ngb-tabset .tab-content {
margin-left: 10px; margin-left: 10px;
} }
} }
select.form-control {
-webkit-appearance: none;
background-image: url("data:image/svg+xml;utf8,<svg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='24' height='24' viewBox='0 0 24 24'><path fill='#444' d='M7.406 7.828l4.594 4.594 4.594-4.594 1.406 1.406-6 6-6-6z'></path></svg>");
background-position: 100% 50%;
background-repeat: no-repeat;
padding-right: 30px;
}
checkbox i.on {
color: $blue;
}

View File

@@ -1,5 +1,10 @@
:host { :host {
display: flex; display: flex;
flex-wrap: nowrap;
&:hover .add {
display: initial;
}
} }
.item { .item {
@@ -22,4 +27,5 @@
.add { .add {
flex: auto; flex: auto;
display: none;
} }

View File

@@ -5,6 +5,7 @@ ngb-tabset.vertical(type='tabs', [activeId]='activeTab')
ng-template(ngbTabTitle) ng-template(ngbTabTitle)
| Application | Application
ng-template(ngbTabContent) ng-template(ngbTabContent)
h3.mb-3 Application
.row .row
.col.col-lg-6 .col.col-lg-6
.form-group .form-group
@@ -168,6 +169,7 @@ ngb-tabset.vertical(type='tabs', [activeId]='activeTab')
ng-template(ngbTabTitle) ng-template(ngbTabTitle)
| Hotkeys | Hotkeys
ng-template(ngbTabContent) ng-template(ngbTabContent)
h3.mb-3 Hotkeys
input.form-control(type='search', placeholder='Search hotkeys', [(ngModel)]='hotkeyFilter') input.form-control(type='search', placeholder='Search hotkeys', [(ngModel)]='hotkeyFilter')
.form-group .form-group
table.hotkeys-table table.hotkeys-table

View File

@@ -1,5 +1,158 @@
h3.mb-2 Appearance h3.mb-3 Appearance
.row .row
.col-md-6
.form-group
label Font
.row
.col-8
input.form-control(
type='text',
[ngbTypeahead]='fontAutocomplete',
[(ngModel)]='config.store.terminal.font',
(ngModelChange)='config.save()',
)
.col-4
input.form-control(
type='number',
[(ngModel)]='config.store.terminal.fontSize',
(ngModelChange)='config.save()',
)
div
checkbox(
text='Enable font ligatures',
[(ngModel)]='config.store.terminal.ligatures',
(ngModelChange)='config.save()',
)
.form-group(*ngIf='!editingColorScheme')
label Color scheme
.input-group
select.form-control(
[compareWith]='equalComparator',
[(ngModel)]='config.store.terminal.colorScheme',
(ngModelChange)='config.save()',
)
option(*ngFor='let scheme of config.store.terminal.customColorSchemes', [ngValue]='scheme') Custom: {{scheme.name}}
option(*ngFor='let scheme of colorSchemes', [ngValue]='scheme') {{scheme.name}}
.input-group-btn
button.btn.btn-secondary((click)='editScheme(config.store.terminal.colorScheme)') Edit
.input-group-btn
button.btn.btn-outline-danger(
(click)='deleteScheme(config.store.terminal.colorScheme)',
*ngIf='isCustomScheme(config.store.terminal.colorScheme)'
)
i.fa.fa-trash-o
.form-group(*ngIf='editingColorScheme')
label Editing
.input-group
input.form-control(type='text', [(ngModel)]='editingColorScheme.name')
.input-group-btn
button.btn.btn-secondary((click)='saveScheme()') Save
.input-group-btn
button.btn.btn-secondary((click)='cancelEditing()') Cancel
.form-group(*ngIf='editingColorScheme')
color-picker(
'[(model)]'='editingColorScheme.foreground',
(modelChange)='config.save(); schemeChanged = true',
title='FG',
)
color-picker(
'[(model)]'='editingColorScheme.background',
(modelChange)='config.save(); schemeChanged = true',
title='BG',
)
color-picker(
'[(model)]'='editingColorScheme.cursor',
(modelChange)='config.save(); schemeChanged = true',
title='CU',
)
color-picker(
*ngFor='let _ of editingColorScheme.colors; let idx = index; trackBy: colorsTrackBy',
'[(model)]'='editingColorScheme.colors[idx]',
(modelChange)='config.save(); schemeChanged = true',
[title]='idx',
)
.form-group
label Terminal background
br
.btn-group(
[(ngModel)]='config.store.terminal.background',
(ngModelChange)='config.save()',
ngbRadioGroup
)
label.btn.btn-secondary(ngbButtonLabel)
input(
type='radio',
ngbButton,
[value]='"theme"'
)
| From theme
label.btn.btn-secondary(ngbButtonLabel)
input(
type='radio',
ngbButton,
[value]='"colorScheme"'
)
| From colors
.d-flex
.form-group.mr-3
label Cursor shape
br
.btn-group(
[(ngModel)]='config.store.terminal.cursor',
(ngModelChange)='config.save()',
ngbRadioGroup
)
label.btn.btn-secondary(ngbButtonLabel)
input(
type='radio',
ngbButton,
[value]='"block"'
)
| █
label.btn.btn-secondary(ngbButtonLabel)
input(
type='radio',
ngbButton,
[value]='"beam"'
)
| |
label.btn.btn-secondary(ngbButtonLabel)
input(
type='radio',
ngbButton,
[value]='"underline"'
)
| ▁
.form-group
label Blink cursor
br
.btn-group(
[(ngModel)]='config.store.terminal.cursorBlink',
(ngModelChange)='config.save()',
ngbRadioGroup
)
label.btn.btn-secondary(ngbButtonLabel)
input(
type='radio',
ngbButton,
[value]='false'
)
| Off
label.btn.btn-secondary(ngbButtonLabel)
input(
type='radio',
ngbButton,
[value]='true'
)
| On
.col-md-6 .col-md-6
.form-group .form-group
.appearance-preview( .appearance-preview(
@@ -7,6 +160,8 @@ h3.mb-2 Appearance
[style.font-size]='config.store.terminal.fontSize + "px"', [style.font-size]='config.store.terminal.fontSize + "px"',
[style.background-color]='(config.store.terminal.background == "theme") ? null : config.store.terminal.colorScheme.background', [style.background-color]='(config.store.terminal.background == "theme") ? null : config.store.terminal.colorScheme.background',
[style.color]='config.store.terminal.colorScheme.foreground', [style.color]='config.store.terminal.colorScheme.foreground',
[style.font-feature-settings]='\'"liga" \' + config.store.terminal.ligatures ? 1 : 0',
[style.font-variant-ligatures]='config.store.terminal.ligatures ? "initial" : "none"',
) )
div div
span([style.background-color]='config.store.terminal.colorScheme.colors[0]') &nbsp; span([style.background-color]='config.store.terminal.colorScheme.colors[0]') &nbsp;
@@ -85,133 +240,7 @@ h3.mb-2 Appearance
span rm -rf / span rm -rf /
span([style.background-color]='config.store.terminal.colorScheme.cursor') &nbsp; span([style.background-color]='config.store.terminal.colorScheme.cursor') &nbsp;
h3.mt-3.mb-3 Shell
.col-md-6
.form-group
label Font
.row
.col-8
input.form-control(
type='text',
[ngbTypeahead]='fontAutocomplete',
'[(ngModel)]'='config.store.terminal.font',
(ngModelChange)='config.save()',
)
.col-4
input.form-control(
type='number',
'[(ngModel)]'='config.store.terminal.fontSize',
(ngModelChange)='config.save()',
)
small.form-text.text-muted Font to be used in the terminal
.form-group(*ngIf='!editingColorScheme')
label Color scheme
.input-group
select.form-control(
[compareWith]='equalComparator',
'[(ngModel)]'='config.store.terminal.colorScheme',
(ngModelChange)='config.save()',
)
option(*ngFor='let scheme of config.store.terminal.customColorSchemes', [ngValue]='scheme') Custom: {{scheme.name}}
option(*ngFor='let scheme of colorSchemes', [ngValue]='scheme') {{scheme.name}}
.input-group-btn
button.btn.btn-secondary((click)='editScheme(config.store.terminal.colorScheme)') Edit
.input-group-btn
button.btn.btn-outline-danger(
(click)='deleteScheme(config.store.terminal.colorScheme)',
*ngIf='isCustomScheme(config.store.terminal.colorScheme)'
)
i.fa.fa-trash-o
.form-group(*ngIf='editingColorScheme')
label Editing
.input-group
input.form-control(type='text', '[(ngModel)]'='editingColorScheme.name')
.input-group-btn
button.btn.btn-secondary((click)='saveScheme()') Save
.input-group-btn
button.btn.btn-secondary((click)='cancelEditing()') Cancel
.form-group(*ngIf='editingColorScheme')
color-picker(
'[(model)]'='editingColorScheme.foreground',
(modelChange)='config.save(); schemeChanged = true',
title='FG',
)
color-picker(
'[(model)]'='editingColorScheme.background',
(modelChange)='config.save(); schemeChanged = true',
title='BG',
)
color-picker(
'[(model)]'='editingColorScheme.cursor',
(modelChange)='config.save(); schemeChanged = true',
title='CU',
)
color-picker(
*ngFor='let _ of editingColorScheme.colors; let idx = index; trackBy: colorsTrackBy',
'[(model)]'='editingColorScheme.colors[idx]',
(modelChange)='config.save(); schemeChanged = true',
[title]='idx',
)
.d-flex
.form-group.mr-3
label Terminal background
br
.btn-group(
'[(ngModel)]'='config.store.terminal.background',
(ngModelChange)='config.save()',
ngbRadioGroup
)
label.btn.btn-secondary(ngbButtonLabel)
input(
type='radio',
ngbButton,
[value]='"theme"'
)
| From theme
label.btn.btn-secondary(ngbButtonLabel)
input(
type='radio',
ngbButton,
[value]='"colorScheme"'
)
| From colors
.form-group
label Cursor shape
br
.btn-group(
[(ngModel)]='config.store.terminal.cursor',
(ngModelChange)='config.save()',
ngbRadioGroup
)
label.btn.btn-secondary(ngbButtonLabel)
input(
type='radio',
ngbButton,
[value]='"block"'
)
| █
label.btn.btn-secondary(ngbButtonLabel)
input(
type='radio',
ngbButton,
[value]='"beam"'
)
| |
label.btn.btn-secondary(ngbButtonLabel)
input(
type='radio',
ngbButton,
[value]='"underline"'
)
| ▁
h3.mt-2.mb-2 Behaviour
.row .row
.col-md-6 .col-md-6
@@ -219,7 +248,7 @@ h3.mt-2.mb-2 Behaviour
.form-group.mr-3 .form-group.mr-3
label Shell label Shell
select.form-control( select.form-control(
'[(ngModel)]'='config.store.terminal.shell', [(ngModel)]='config.store.terminal.shell',
(ngModelChange)='config.save()', (ngModelChange)='config.save()',
) )
option( option(
@@ -227,10 +256,10 @@ h3.mt-2.mb-2 Behaviour
[ngValue]='shell.id' [ngValue]='shell.id'
) {{shell.name}} ) {{shell.name}}
.form-group .form-group(*ngIf='persistenceProviders.length > 0')
label Session persistence label Session persistence
select.form-control( select.form-control(
'[(ngModel)]'='config.store.terminal.persistence', [(ngModel)]='config.store.terminal.persistence',
(ngModelChange)='config.save()', (ngModelChange)='config.save()',
) )
option([ngValue]='null') Off option([ngValue]='null') Off
@@ -243,140 +272,93 @@ h3.mt-2.mb-2 Behaviour
label Custom shell label Custom shell
input.form-control( input.form-control(
type='text', type='text',
'[(ngModel)]'='config.store.terminal.customShell', [(ngModel)]='config.store.terminal.customShell',
(ngModelChange)='config.save()', (ngModelChange)='config.save()',
) )
.col-md-6
.form-group .form-group
label Working directory label Working directory
input.form-control( input.form-control(
type='text', type='text',
placeholder='Home directory', placeholder='Home directory',
'[(ngModel)]'='config.store.terminal.workingDirectory', [(ngModel)]='config.store.terminal.workingDirectory',
(ngModelChange)='config.save()', (ngModelChange)='config.save()',
) )
.form-group h3.mt-3.mb-3 Behaviour
label Auto-open a terminal on app start
br .form-group
.btn-group( label Terminal bell
'[(ngModel)]'='config.store.terminal.autoOpen', br
(ngModelChange)='config.save()', .btn-group(
ngbRadioGroup [(ngModel)]='config.store.terminal.bell',
(ngModelChange)='config.save()',
ngbRadioGroup
)
label.btn.btn-secondary(ngbButtonLabel)
input(
type='radio',
ngbButton,
[value]='"off"'
) )
label.btn.btn-secondary(ngbButtonLabel) | Off
input( label.btn.btn-secondary(ngbButtonLabel)
type='radio', input(
ngbButton, type='radio',
[value]='false' ngbButton,
) [value]='"visual"'
| Off )
label.btn.btn-secondary(ngbButtonLabel) | Visual
input( label.btn.btn-secondary(ngbButtonLabel)
type='radio', input(
ngbButton, type='radio',
[value]='true' ngbButton,
) [value]='"audible"'
| On )
| Audible
.col-md-6
.d-flex .form-group
.form-group.mr-3 label Right click behaviour
label Terminal bell br
br .btn-group(
.btn-group( [(ngModel)]='config.store.terminal.rightClick',
'[(ngModel)]'='config.store.terminal.bell', (ngModelChange)='config.save()',
(ngModelChange)='config.save()', ngbRadioGroup
ngbRadioGroup )
) label.btn.btn-secondary(ngbButtonLabel)
label.btn.btn-secondary(ngbButtonLabel) input(
input( type='radio',
type='radio', ngbButton,
ngbButton, value='menu'
[value]='"off"' )
) | Context menu
| Off label.btn.btn-secondary(ngbButtonLabel)
label.btn.btn-secondary(ngbButtonLabel) input(
input( type='radio',
type='radio', ngbButton,
ngbButton, value='paste'
[value]='"visual"' )
) | Paste
| Visual
label.btn.btn-secondary(ngbButtonLabel)
input( .form-group
type='radio', checkbox(
ngbButton, [(ngModel)]='config.store.terminal.autoOpen',
[value]='"audible"' (ngModelChange)='config.save()',
) text='Auto-open a terminal on app start',
| Audible )
.form-group checkbox(
label Blink cursor [(ngModel)]='config.store.terminal.bracketedPaste',
br (ngModelChange)='config.save()',
.btn-group( text='Bracketed paste (requires shell support)',
'[(ngModel)]'='config.store.terminal.cursorBlink', )
(ngModelChange)='config.save()',
ngbRadioGroup checkbox(
) [(ngModel)]='config.store.terminal.copyOnSelect',
label.btn.btn-secondary(ngbButtonLabel) (ngModelChange)='config.save()',
input( text='Copy on select',
type='radio', )
ngbButton,
[value]='false'
)
| Off
label.btn.btn-secondary(ngbButtonLabel)
input(
type='radio',
ngbButton,
[value]='true'
)
| On
.d-flex
.form-group.mr-3
label Copy on select
br
.btn-group(
'[(ngModel)]'='config.store.terminal.copyOnSelect',
(ngModelChange)='config.save()',
ngbRadioGroup
)
label.btn.btn-secondary(ngbButtonLabel)
input(
type='radio',
ngbButton,
[value]='false'
)
| Off
label.btn.btn-secondary(ngbButtonLabel)
input(
type='radio',
ngbButton,
[value]='true'
)
| On
.form-group
label Right click behaviour
br
.btn-group(
'[(ngModel)]'='config.store.terminal.rightClick',
(ngModelChange)='config.save()',
ngbRadioGroup
)
label.btn.btn-secondary(ngbButtonLabel)
input(
type='radio',
ngbButton,
value='menu'
)
| Menu
label.btn.btn-secondary(ngbButtonLabel)
input(
type='radio',
ngbButton,
value='paste'
)
| Paste

View File

@@ -1,5 +1,6 @@
.appearance-preview { .appearance-preview {
padding: 10px 20px; padding: 10px 0;
margin-left: 30px;
margin: 0 0 10px; margin: 0 0 10px;
overflow: hidden; overflow: hidden;
span { span {

View File

@@ -56,5 +56,9 @@ export class TerminalHotkeyProvider extends HotkeyProvider {
id: 'new-tab', id: 'new-tab',
name: 'New tab', name: 'New tab',
}, },
{
id: 'ctrl-c',
name: 'Intelligent Ctrl-C (copy/abort)',
},
] ]
} }

View File

@@ -3,6 +3,7 @@ import { BrowserModule } from '@angular/platform-browser'
import { FormsModule } from '@angular/forms' import { FormsModule } from '@angular/forms'
import { NgbModule } from '@ng-bootstrap/ng-bootstrap' import { NgbModule } from '@ng-bootstrap/ng-bootstrap'
import { ToastrModule } from 'ngx-toastr' import { ToastrModule } from 'ngx-toastr'
import TerminusCorePlugin from 'terminus-core'
import { ToolbarButtonProvider, TabRecoveryProvider, ConfigProvider, HotkeysService, HotkeyProvider, AppService, ConfigService } from 'terminus-core' import { ToolbarButtonProvider, TabRecoveryProvider, ConfigProvider, HotkeysService, HotkeyProvider, AppService, ConfigService } from 'terminus-core'
import { SettingsTabProvider } from 'terminus-settings' import { SettingsTabProvider } from 'terminus-settings'
@@ -43,6 +44,7 @@ import { hterm } from './hterm'
FormsModule, FormsModule,
NgbModule, NgbModule,
ToastrModule, ToastrModule,
TerminusCorePlugin,
], ],
providers: [ providers: [
SessionsService, SessionsService,