mirror of
https://github.com/Eugeny/tabby.git
synced 2024-12-22 18:11:43 +03:00
.
This commit is contained in:
parent
482343e383
commit
cb7e1cd157
@ -1,541 +0,0 @@
|
|||||||
@import (less, reference) "../../../node_modules/font-awesome/css/font-awesome.css";
|
|
||||||
|
|
||||||
|
|
||||||
.glyphicon:extend(.fa all) {
|
|
||||||
&.glyphicon-chevron-right:extend(.fa-chevron-right all) {};
|
|
||||||
&.glyphicon-chevron-left:extend(.fa-chevron-left all) {};
|
|
||||||
&.glyphicon-chevron-up:extend(.fa-chevron-up all) {};
|
|
||||||
&.glyphicon-chevron-down:extend(.fa-chevron-down all) {};
|
|
||||||
}
|
|
||||||
|
|
||||||
h4 {
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: #EFEAB1;
|
|
||||||
transition: opacity 0.125s, background 0.125s, color0.125s ;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: #FFF79A;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.block-element {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
textarea {
|
|
||||||
resize: vertical;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn {
|
|
||||||
border: none !important;
|
|
||||||
box-shadow: 0 1px 1px rgba(0,0,0,.125);
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
outline: 5px auto @brand-info;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:active,
|
|
||||||
&.active {
|
|
||||||
.box-shadow(@control-shadow-active);
|
|
||||||
}
|
|
||||||
|
|
||||||
-webkit-transition: all 0.125s ease-out;
|
|
||||||
-moz-transition: all 0.125s ease-out;
|
|
||||||
-ms-transition: all 0.125s ease-out;
|
|
||||||
-o-transition: all 0.125s ease-out;
|
|
||||||
transition: all 0.125s ease-out;
|
|
||||||
|
|
||||||
&[disabled] {
|
|
||||||
cursor: default !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-ink {
|
|
||||||
background: transparent !important;
|
|
||||||
box-shadow: none;
|
|
||||||
|
|
||||||
&.btn-danger {
|
|
||||||
color: #FF4832;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.btn-xs {
|
|
||||||
padding-top: 0;
|
|
||||||
padding-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-toolbar {
|
|
||||||
margin: 0;
|
|
||||||
|
|
||||||
.btn, .btn-group, [uib-dropdown] {
|
|
||||||
float: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .btn-group > * {
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .btn, > .btn-group, > [uib-dropdown] {
|
|
||||||
margin: 0 5px 5px 0px;
|
|
||||||
vertical-align: top;
|
|
||||||
|
|
||||||
> .btn {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: @screen-xs-max) {
|
|
||||||
.btn-toolbar-collapsible {
|
|
||||||
.btn {
|
|
||||||
font-size: 0;
|
|
||||||
|
|
||||||
.fa::before, .caret {
|
|
||||||
font-size: @font-size-base;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[uib-dropdown] {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
[uib-dropdown-menu], .dropdown-menu {
|
|
||||||
.box-shadow(@control-dropdown-shadow);
|
|
||||||
top: 25px;
|
|
||||||
|
|
||||||
> li > * {
|
|
||||||
display: block;
|
|
||||||
padding: 5px 20px;
|
|
||||||
clear: both;
|
|
||||||
font-weight: normal;
|
|
||||||
line-height: @line-height-base;
|
|
||||||
color: @dropdown-link-color;
|
|
||||||
white-space: nowrap;
|
|
||||||
|
|
||||||
&[disabled] {
|
|
||||||
color: #888;
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> li.disabled a {
|
|
||||||
color: #666;
|
|
||||||
&:hover {
|
|
||||||
color: #666;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[uib-dropdown-menu] > .active > * {
|
|
||||||
&,
|
|
||||||
&:hover,
|
|
||||||
&:focus {
|
|
||||||
color: @dropdown-link-active-color;
|
|
||||||
text-decoration: none;
|
|
||||||
outline: 0;
|
|
||||||
background-color: @dropdown-link-active-bg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.form-control {
|
|
||||||
border: none;
|
|
||||||
|
|
||||||
&[checkbox] {
|
|
||||||
border: none;
|
|
||||||
background: transparent;
|
|
||||||
display: inline-block;
|
|
||||||
margin: @padding-base-vertical 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
border-radius: 0;
|
|
||||||
.box-shadow(~"0 1px 1px rgba(0, 0, 0, 0.51)");
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
.box-shadow(~"0 1px 1px rgba(0, 0, 0, 0.51)");
|
|
||||||
}
|
|
||||||
|
|
||||||
.transition(0.25s background);
|
|
||||||
|
|
||||||
&::-webkit-input-placeholder {
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-group {
|
|
||||||
.box-shadow(~"0 1px 1px rgba(0, 0, 0, 0.51)");
|
|
||||||
.form-control {
|
|
||||||
.box-shadow(none);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-group-addon {
|
|
||||||
border: none;
|
|
||||||
padding: 6px 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: @screen-sm-min) {
|
|
||||||
.control-label {
|
|
||||||
font-size: 12px;
|
|
||||||
padding-top: 10px;
|
|
||||||
font-weight: normal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-group .control-label {
|
|
||||||
font-size: 12px;
|
|
||||||
padding-top: 10px;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #777;
|
|
||||||
}
|
|
||||||
|
|
||||||
label.form-control-static {
|
|
||||||
font-size: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-group {
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
*:focus + .input-group-addon,
|
|
||||||
*:focus + .input-group-btn {
|
|
||||||
//border-bottom: 1px solid @brand-primary;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-group-addon, .input-group-btn {
|
|
||||||
border: none;
|
|
||||||
|
|
||||||
&.input-sm {
|
|
||||||
border-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
margin: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
text-decoration: none !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.label {
|
|
||||||
font-size: 76%;
|
|
||||||
position: relative;
|
|
||||||
padding: 5px 4px 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.list-group {
|
|
||||||
.box-shadow(@control-shadow);
|
|
||||||
}
|
|
||||||
|
|
||||||
.list-group-item {
|
|
||||||
border: none;
|
|
||||||
border-top: 1px solid @list-group-line-border;
|
|
||||||
cursor: default;
|
|
||||||
|
|
||||||
&:first-child {
|
|
||||||
border-top: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
color: #f7e61d;
|
|
||||||
border-right: 2px solid #f7e61d;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.list-group-item.combi {
|
|
||||||
padding: 0;
|
|
||||||
clear: both;
|
|
||||||
|
|
||||||
tr& {
|
|
||||||
a.main, .btn {
|
|
||||||
display: table-cell !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
& > .main {
|
|
||||||
display: block;
|
|
||||||
|
|
||||||
h4 {
|
|
||||||
margin-top: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre {
|
|
||||||
background: transparent;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
video-thumbnail, asset-thumbnail {
|
|
||||||
margin-right: 15px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
& > a.main {
|
|
||||||
cursor: pointer;
|
|
||||||
color: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
& > a.main, & > a.btn, & > button, & > [uib-dropdown] > button {
|
|
||||||
&:hover,
|
|
||||||
&:focus {
|
|
||||||
text-decoration: none;
|
|
||||||
color: @list-group-link-hover-color;
|
|
||||||
background-color: @list-group-hover-bg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
& > a.btn, & > button, & > [uib-dropdown] > button {
|
|
||||||
background-color: @list-group-bg;
|
|
||||||
position: relative; // more z-index
|
|
||||||
z-index: 2;
|
|
||||||
display: block;
|
|
||||||
float: right;
|
|
||||||
border: none;
|
|
||||||
margin: 0;
|
|
||||||
box-shadow: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
& > .drag-handle {
|
|
||||||
float: left;
|
|
||||||
cursor: move;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.single > .main {
|
|
||||||
height: 40px;
|
|
||||||
line-height: 39px;
|
|
||||||
padding: 0 15px;
|
|
||||||
|
|
||||||
[checkbox] {
|
|
||||||
display: inline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.label-lg {
|
|
||||||
top: 7px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.double > .main {
|
|
||||||
height: 68px;
|
|
||||||
line-height: 25px;
|
|
||||||
padding: 10px 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.single {
|
|
||||||
a.btn, button, .drag-handle {
|
|
||||||
padding: 10px 12px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.double {
|
|
||||||
a.btn, button, .drag-handle {
|
|
||||||
padding: 24px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.form-control-focus(@color: @input-border-focus) {
|
|
||||||
@color-rgba: rgba(red(@color), green(@color), blue(@color), .3);
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal {
|
|
||||||
background-color: rgba(0,0,0,.5);
|
|
||||||
position: fixed !important;
|
|
||||||
|
|
||||||
|
|
||||||
.modal-dialog {
|
|
||||||
margin: 0 auto;
|
|
||||||
top: 50px;
|
|
||||||
|
|
||||||
.modal-content {
|
|
||||||
background-color: @body-bg;
|
|
||||||
|
|
||||||
|
|
||||||
.modal-body {
|
|
||||||
max-height: 80vh;
|
|
||||||
overflow-y: auto;
|
|
||||||
padding: 25px 15px;
|
|
||||||
-webkit-app-region: no-drag;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-footer {
|
|
||||||
border-top: 1px solid #222;
|
|
||||||
padding: 0;
|
|
||||||
-webkit-app-region: no-drag;
|
|
||||||
|
|
||||||
.btn.btn-default {
|
|
||||||
background: @input-bg;
|
|
||||||
border: none !important;
|
|
||||||
cursor: pointer;
|
|
||||||
box-shadow: none !important;
|
|
||||||
padding: 10px;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: rgba(0,0,0,.25);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
background: rgba(0,0,0,.5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-backdrop {
|
|
||||||
background: rgba(0,0,0,.25);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.navbar-fixed-top {
|
|
||||||
border-width: 0 0 2px;
|
|
||||||
height: 52px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navbar-form {
|
|
||||||
box-shadow: none !important;
|
|
||||||
border: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-tabs-justified,
|
|
||||||
.nav-tabs {
|
|
||||||
border-bottom: 1px solid @nav-tabs-border-color;
|
|
||||||
|
|
||||||
> li {
|
|
||||||
> a {
|
|
||||||
border: 1px solid transparent;
|
|
||||||
border-radius: 0;
|
|
||||||
color: @text-color;
|
|
||||||
&:hover {
|
|
||||||
background-color: @nav-tabs-active-link-hover-bg;
|
|
||||||
border-bottom: 1px solid @nav-tabs-border-color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Active state, and its :hover to override normal :hover
|
|
||||||
&.active > a {
|
|
||||||
&,
|
|
||||||
&:hover,
|
|
||||||
&:focus {
|
|
||||||
border-radius: 0;
|
|
||||||
border: 1px solid transparent;
|
|
||||||
border-bottom: 1px solid @nav-tabs-active-link-hover-border-color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-justified {
|
|
||||||
> li {
|
|
||||||
display: table-cell;
|
|
||||||
width: 1%;
|
|
||||||
> a {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.popover-content {
|
|
||||||
//padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
table {
|
|
||||||
background: transparent;
|
|
||||||
|
|
||||||
td {
|
|
||||||
vertical-align: top;
|
|
||||||
}
|
|
||||||
|
|
||||||
.table-condensed {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.table {
|
|
||||||
background: @table-bg;
|
|
||||||
.box-shadow(@control-shadow);
|
|
||||||
&.no-margin {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
> thead,
|
|
||||||
> tbody,
|
|
||||||
> tfoot {
|
|
||||||
> tr {
|
|
||||||
background-color: transparent;
|
|
||||||
> th,
|
|
||||||
> td {
|
|
||||||
border-top: 1px solid @table-line-border-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:first-child {
|
|
||||||
th, td {
|
|
||||||
border-top: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
> thead > tr > th {
|
|
||||||
border-bottom: 2px solid @table-line-border-color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.table-bordered {
|
|
||||||
> thead,
|
|
||||||
> tbody,
|
|
||||||
> tfoot {
|
|
||||||
> tr {
|
|
||||||
> th,
|
|
||||||
> td {
|
|
||||||
border: 1px solid @table-line-border-color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.help-block {
|
|
||||||
color: darken(@text-color, 10%);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.label {
|
|
||||||
margin-right: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.datepicker-dropdown {
|
|
||||||
&.datepicker-orient-top:before {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.datepicker-orient-top:after {
|
|
||||||
border-bottom: 7px solid @dropdown-bg !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.datepicker-orient-bottom:after {
|
|
||||||
border-top: 7px solid @dropdown-bg !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
table tr td.day:hover {
|
|
||||||
background: #555 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
table tr td.active {
|
|
||||||
background: @brand-primary !important;
|
|
||||||
color: #222 !important;
|
|
||||||
text-shadow: none !important;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,15 +1,9 @@
|
|||||||
appearance:
|
appearance:
|
||||||
font: monospace
|
|
||||||
fontSize: 14
|
|
||||||
dock: 'off'
|
dock: 'off'
|
||||||
dockScreen: 'current'
|
dockScreen: 'current'
|
||||||
dockFill: 50
|
dockFill: 50
|
||||||
tabsOnTop: true
|
tabsOnTop: true
|
||||||
hotkeys:
|
hotkeys:
|
||||||
new-tab:
|
|
||||||
- ['Ctrl-A', 'C']
|
|
||||||
- ['Ctrl-A', 'Ctrl-C']
|
|
||||||
- 'Ctrl-Shift-T'
|
|
||||||
close-tab:
|
close-tab:
|
||||||
- 'Ctrl-Shift-W'
|
- 'Ctrl-Shift-W'
|
||||||
- ['Ctrl-A', 'K']
|
- ['Ctrl-A', 'K']
|
||||||
@ -52,5 +46,3 @@ hotkeys:
|
|||||||
tab-10:
|
tab-10:
|
||||||
- 'Alt-0'
|
- 'Alt-0'
|
||||||
- ['Ctrl-A', '0']
|
- ['Ctrl-A', '0']
|
||||||
terminal:
|
|
||||||
bell: off
|
|
||||||
|
4
app/src/api/configProvider.ts
Normal file
4
app/src/api/configProvider.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export abstract class ConfigProvider {
|
||||||
|
configStructure: any = {}
|
||||||
|
defaultConfigValues: any = {}
|
||||||
|
}
|
8
app/src/api/hotkeyProvider.ts
Normal file
8
app/src/api/hotkeyProvider.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
export interface IHotkeyDescription {
|
||||||
|
id: string,
|
||||||
|
name: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export abstract class HotkeyProvider {
|
||||||
|
hotkeys: IHotkeyDescription[] = []
|
||||||
|
}
|
@ -1,7 +1,10 @@
|
|||||||
export { Tab } from './tab'
|
export { Tab } from './tab'
|
||||||
export { TabRecoveryProvider } from './tabRecovery'
|
export { TabRecoveryProvider } from './tabRecovery'
|
||||||
export { ToolbarButtonProvider, IToolbarButton } from './toolbarButtonProvider'
|
export { ToolbarButtonProvider, IToolbarButton } from './toolbarButtonProvider'
|
||||||
|
export { ConfigProvider } from './configProvider'
|
||||||
|
export { HotkeyProvider, IHotkeyDescription } from './hotkeyProvider'
|
||||||
|
|
||||||
export { AppService } from 'services/app'
|
export { AppService } from 'services/app'
|
||||||
export { PluginsService } from 'services/plugins'
|
export { PluginsService } from 'services/plugins'
|
||||||
export { ElectronService } from 'services/electron'
|
export { ElectronService } from 'services/electron'
|
||||||
|
export { HotkeysService } from 'services/hotkeys'
|
||||||
|
@ -10,7 +10,7 @@ import { ConfigService } from 'services/config'
|
|||||||
import { ElectronService } from 'services/electron'
|
import { ElectronService } from 'services/electron'
|
||||||
import { HostAppService } from 'services/hostApp'
|
import { HostAppService } from 'services/hostApp'
|
||||||
import { LogService } from 'services/log'
|
import { LogService } from 'services/log'
|
||||||
import { HotkeysService } from 'services/hotkeys'
|
import { HotkeysService, AppHotkeyProvider } from 'services/hotkeys'
|
||||||
import { ModalService } from 'services/modal'
|
import { ModalService } from 'services/modal'
|
||||||
import { NotifyService } from 'services/notify'
|
import { NotifyService } from 'services/notify'
|
||||||
import { PluginsService } from 'services/plugins'
|
import { PluginsService } from 'services/plugins'
|
||||||
@ -23,6 +23,8 @@ import { TabBodyComponent } from 'components/tabBody'
|
|||||||
import { TabHeaderComponent } from 'components/tabHeader'
|
import { TabHeaderComponent } from 'components/tabHeader'
|
||||||
import { TitleBarComponent } from 'components/titleBar'
|
import { TitleBarComponent } from 'components/titleBar'
|
||||||
|
|
||||||
|
import { HotkeyProvider } from 'api/hotkeyProvider'
|
||||||
|
|
||||||
|
|
||||||
let plugins = [
|
let plugins = [
|
||||||
require('./settings').default,
|
require('./settings').default,
|
||||||
@ -50,6 +52,7 @@ let plugins = [
|
|||||||
NotifyService,
|
NotifyService,
|
||||||
PluginsService,
|
PluginsService,
|
||||||
QuitterService,
|
QuitterService,
|
||||||
|
{ provide: HotkeyProvider, useClass: AppHotkeyProvider, multi: true },
|
||||||
],
|
],
|
||||||
entryComponents: [
|
entryComponents: [
|
||||||
],
|
],
|
||||||
@ -65,7 +68,4 @@ let plugins = [
|
|||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class AppModule {
|
export class AppModule {
|
||||||
constructor () {
|
|
||||||
//pluginDispatcher.register(require('./plugin.hyperlinks').default)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ import { DockingService } from 'services/docking'
|
|||||||
import { AppService, IToolbarButton, ToolbarButtonProvider } from 'api'
|
import { AppService, IToolbarButton, ToolbarButtonProvider } from 'api'
|
||||||
|
|
||||||
import 'angular2-toaster/lib/toaster.css'
|
import 'angular2-toaster/lib/toaster.css'
|
||||||
|
import 'overrides.scss'
|
||||||
import 'global.less'
|
import 'global.less'
|
||||||
import 'theme.scss'
|
import 'theme.scss'
|
||||||
|
|
||||||
@ -65,9 +66,6 @@ export class AppRootComponent {
|
|||||||
})
|
})
|
||||||
|
|
||||||
this.hotkeys.matchedHotkey.subscribe((hotkey) => {
|
this.hotkeys.matchedHotkey.subscribe((hotkey) => {
|
||||||
if (hotkey == 'new-tab') {
|
|
||||||
// TODO this.newTab()
|
|
||||||
}
|
|
||||||
if (hotkey.startsWith('tab-')) {
|
if (hotkey.startsWith('tab-')) {
|
||||||
let index = parseInt(hotkey.split('-')[1])
|
let index = parseInt(hotkey.split('-')[1])
|
||||||
if (index <= this.app.tabs.length) {
|
if (index <= this.app.tabs.length) {
|
||||||
|
@ -66,24 +66,6 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ngb-modal-backdrop {
|
|
||||||
// ngbmodalwindow has its own, properly animated backdrop
|
|
||||||
background: transparent !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
ngb-modal-window.fade.in {
|
|
||||||
&.out {
|
|
||||||
opacity: 0;
|
|
||||||
|
|
||||||
.modal-dialog {
|
|
||||||
transform: translate(0, -25%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.btn {
|
.btn {
|
||||||
i + * {
|
i + * {
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
|
9
app/src/overrides.scss
Normal file
9
app/src/overrides.scss
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
ngb-tabset.vertical {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
> .nav {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex: none;
|
||||||
|
}
|
||||||
|
}
|
@ -1,69 +1,54 @@
|
|||||||
import * as yaml from 'js-yaml'
|
import * as yaml from 'js-yaml'
|
||||||
import * as path from 'path'
|
import * as path from 'path'
|
||||||
import * as fs from 'fs'
|
import * as fs from 'fs'
|
||||||
import { EventEmitter, Injectable } from '@angular/core'
|
import { EventEmitter, Injectable, Inject } from '@angular/core'
|
||||||
import { ElectronService } from 'services/electron'
|
import { ElectronService } from 'services/electron'
|
||||||
|
import { ConfigProvider } from 'api/configProvider'
|
||||||
|
|
||||||
const configMerge = (a, b) => require('deepmerge')(a, b, { arrayMerge: (_d, s) => s })
|
const configMerge = (a, b) => require('deepmerge')(a, b, { arrayMerge: (_d, s) => s })
|
||||||
const defaultConfigValues : IConfigData = require('../../defaultConfigValues.yaml')
|
|
||||||
const defaultConfigStructure : IConfigData = require('../../defaultConfigStructure.yaml')
|
|
||||||
|
|
||||||
export interface IAppearanceData {
|
|
||||||
useNativeFrame: boolean
|
|
||||||
font: string
|
|
||||||
fontSize: number
|
|
||||||
dock: string
|
|
||||||
dockScreen: string
|
|
||||||
dockFill: number
|
|
||||||
tabsOnTop: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ITerminalData {
|
|
||||||
bell: string|boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IConfigData {
|
|
||||||
appearance?: IAppearanceData
|
|
||||||
hotkeys?: any
|
|
||||||
terminal?: ITerminalData
|
|
||||||
}
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ConfigService {
|
export class ConfigService {
|
||||||
store: IConfigData
|
store: any
|
||||||
change = new EventEmitter()
|
change = new EventEmitter()
|
||||||
restartRequested: boolean
|
restartRequested: boolean
|
||||||
private path: string
|
private path: string
|
||||||
|
private configStructure: any = require('../../defaultConfigStructure.yaml')
|
||||||
|
private defaultConfigValues: any = require('../../defaultConfigValues.yaml')
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
electron: ElectronService
|
electron: ElectronService,
|
||||||
|
@Inject(ConfigProvider) configProviders: ConfigProvider[],
|
||||||
) {
|
) {
|
||||||
this.path = path.join(electron.app.getPath('userData'), 'config.yaml')
|
this.path = path.join(electron.app.getPath('userData'), 'config.yaml')
|
||||||
|
this.configStructure = configProviders.map(x => x.configStructure).reduce(configMerge, this.configStructure)
|
||||||
|
this.defaultConfigValues = configProviders.map(x => x.defaultConfigValues).reduce(configMerge, this.defaultConfigValues)
|
||||||
this.load()
|
this.load()
|
||||||
}
|
}
|
||||||
|
|
||||||
load () {
|
load (): void {
|
||||||
if (fs.existsSync(this.path)) {
|
if (fs.existsSync(this.path)) {
|
||||||
this.store = configMerge(defaultConfigStructure, yaml.safeLoad(fs.readFileSync(this.path, 'utf8')))
|
this.store = configMerge(this.configStructure, yaml.safeLoad(fs.readFileSync(this.path, 'utf8')))
|
||||||
} else {
|
} else {
|
||||||
this.store = Object.assign({}, defaultConfigStructure)
|
this.store = Object.assign({}, this.configStructure)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
save () {
|
save (): void {
|
||||||
fs.writeFileSync(this.path, yaml.safeDump(this.store), 'utf8')
|
fs.writeFileSync(this.path, yaml.safeDump(this.store), 'utf8')
|
||||||
this.emitChange()
|
this.emitChange()
|
||||||
}
|
}
|
||||||
|
|
||||||
full () : IConfigData {
|
full (): any {
|
||||||
return configMerge(defaultConfigValues, this.store)
|
return configMerge(this.defaultConfigValues, this.store)
|
||||||
}
|
}
|
||||||
|
|
||||||
emitChange () {
|
emitChange (): void {
|
||||||
this.change.emit()
|
this.change.emit()
|
||||||
}
|
}
|
||||||
|
|
||||||
requestRestart () {
|
requestRestart (): void {
|
||||||
this.restartRequested = true
|
this.restartRequested = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,10 @@
|
|||||||
import { Injectable, NgZone, EventEmitter } from '@angular/core'
|
import { Injectable, Inject, NgZone, EventEmitter } from '@angular/core'
|
||||||
import { ElectronService } from 'services/electron'
|
import { ElectronService } from 'services/electron'
|
||||||
import { ConfigService } from 'services/config'
|
import { ConfigService } from 'services/config'
|
||||||
import { NativeKeyEvent, stringifyKeySequence } from './hotkeys.util'
|
import { NativeKeyEvent, stringifyKeySequence } from './hotkeys.util'
|
||||||
|
import { IHotkeyDescription, HotkeyProvider } from 'api/hotkeyProvider'
|
||||||
const hterm = require('hterm-commonjs')
|
const hterm = require('hterm-commonjs')
|
||||||
|
|
||||||
export interface HotkeyDescription {
|
|
||||||
id: string,
|
|
||||||
name: string,
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PartialHotkeyMatch {
|
export interface PartialHotkeyMatch {
|
||||||
id: string,
|
id: string,
|
||||||
@ -16,69 +13,6 @@ export interface PartialHotkeyMatch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const KEY_TIMEOUT = 2000
|
const KEY_TIMEOUT = 2000
|
||||||
const HOTKEYS: HotkeyDescription[] = [
|
|
||||||
{
|
|
||||||
id: 'new-tab',
|
|
||||||
name: 'New tab',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'close-tab',
|
|
||||||
name: 'Close tab',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'toggle-last-tab',
|
|
||||||
name: 'Toggle last tab',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'next-tab',
|
|
||||||
name: 'Next tab',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'previous-tab',
|
|
||||||
name: 'Previous tab',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'tab-1',
|
|
||||||
name: 'Tab 1',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'tab-2',
|
|
||||||
name: 'Tab 2',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'tab-3',
|
|
||||||
name: 'Tab 3',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'tab-4',
|
|
||||||
name: 'Tab 4',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'tab-5',
|
|
||||||
name: 'Tab 5',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'tab-6',
|
|
||||||
name: 'Tab 6',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'tab-7',
|
|
||||||
name: 'Tab 7',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'tab-8',
|
|
||||||
name: 'Tab 8',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'tab-9',
|
|
||||||
name: 'Tab 9',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'tab-10',
|
|
||||||
name: 'Tab 10',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
interface EventBufferEntry {
|
interface EventBufferEntry {
|
||||||
event: NativeKeyEvent,
|
event: NativeKeyEvent,
|
||||||
@ -92,11 +26,13 @@ export class HotkeysService {
|
|||||||
globalHotkey = new EventEmitter()
|
globalHotkey = new EventEmitter()
|
||||||
private currentKeystrokes: EventBufferEntry[] = []
|
private currentKeystrokes: EventBufferEntry[] = []
|
||||||
private disabledLevel = 0
|
private disabledLevel = 0
|
||||||
|
private hotkeyDescriptions: IHotkeyDescription[]
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private zone: NgZone,
|
private zone: NgZone,
|
||||||
private electron: ElectronService,
|
private electron: ElectronService,
|
||||||
private config: ConfigService,
|
private config: ConfigService,
|
||||||
|
@Inject(HotkeyProvider) hotkeyProviders: HotkeyProvider[],
|
||||||
) {
|
) {
|
||||||
let events = [
|
let events = [
|
||||||
{
|
{
|
||||||
@ -122,6 +58,7 @@ export class HotkeysService {
|
|||||||
oldHandler.bind(this)(nativeEvent)
|
oldHandler.bind(this)(nativeEvent)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
this.hotkeyDescriptions = hotkeyProviders.map(x => x.hotkeys).reduce((a, b) => a.concat(b))
|
||||||
}
|
}
|
||||||
|
|
||||||
emitNativeEvent (name, nativeEvent) {
|
emitNativeEvent (name, nativeEvent) {
|
||||||
@ -214,8 +151,8 @@ export class HotkeysService {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
getHotkeyDescription (id: string) : HotkeyDescription {
|
getHotkeyDescription (id: string) : IHotkeyDescription {
|
||||||
return HOTKEYS.filter((x) => x.id == id)[0]
|
return this.hotkeyDescriptions.filter((x) => x.id == id)[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
enable () {
|
enable () {
|
||||||
@ -231,3 +168,70 @@ export class HotkeysService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class AppHotkeyProvider extends HotkeyProvider {
|
||||||
|
hotkeys: IHotkeyDescription[] = [
|
||||||
|
{
|
||||||
|
id: 'new-tab',
|
||||||
|
name: 'New tab',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'close-tab',
|
||||||
|
name: 'Close tab',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'toggle-last-tab',
|
||||||
|
name: 'Toggle last tab',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'next-tab',
|
||||||
|
name: 'Next tab',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'previous-tab',
|
||||||
|
name: 'Previous tab',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'tab-1',
|
||||||
|
name: 'Tab 1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'tab-2',
|
||||||
|
name: 'Tab 2',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'tab-3',
|
||||||
|
name: 'Tab 3',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'tab-4',
|
||||||
|
name: 'Tab 4',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'tab-5',
|
||||||
|
name: 'Tab 5',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'tab-6',
|
||||||
|
name: 'Tab 6',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'tab-7',
|
||||||
|
name: 'Tab 7',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'tab-8',
|
||||||
|
name: 'Tab 8',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'tab-9',
|
||||||
|
name: 'Tab 9',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'tab-10',
|
||||||
|
name: 'Tab 10',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
@ -2,7 +2,7 @@ import { Component } from '@angular/core'
|
|||||||
|
|
||||||
export declare type ComponentType = new (...args: any[]) => Component
|
export declare type ComponentType = new (...args: any[]) => Component
|
||||||
|
|
||||||
export abstract class SettingsProvider {
|
export abstract class SettingsTabProvider {
|
||||||
title: string
|
title: string
|
||||||
|
|
||||||
getComponentType (): ComponentType {
|
getComponentType (): ComponentType {
|
||||||
|
6
app/src/settings/components/multiHotkeyInput.pug
Normal file
6
app/src/settings/components/multiHotkeyInput.pug
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
.item(*ngFor='let item of model')
|
||||||
|
.body((click)='editItem(item)')
|
||||||
|
.stroke(*ngFor='let stroke of item') {{stroke}}
|
||||||
|
.remove((click)='removeItem(item)') ×
|
||||||
|
|
||||||
|
.add((click)='addItem()') Add
|
28
app/src/settings/components/multiHotkeyInput.scss
Normal file
28
app/src/settings/components/multiHotkeyInput.scss
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
:host {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item {
|
||||||
|
display: flex;
|
||||||
|
flex: none;
|
||||||
|
padding: 3px 0;
|
||||||
|
margin-right: 5px;
|
||||||
|
|
||||||
|
.body {
|
||||||
|
flex: none;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
.stroke {
|
||||||
|
flex: none;
|
||||||
|
padding: 0 3px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.remove {
|
||||||
|
flex: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.add {
|
||||||
|
flex: auto;
|
||||||
|
}
|
48
app/src/settings/components/multiHotkeyInput.ts
Normal file
48
app/src/settings/components/multiHotkeyInput.ts
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy } from '@angular/core'
|
||||||
|
import { ModalService } from 'services/modal'
|
||||||
|
import { HotkeyInputModalComponent } from './hotkeyInputModal'
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'multi-hotkey-input',
|
||||||
|
template: require('./multiHotkeyInput.pug'),
|
||||||
|
styles: [require('./multiHotkeyInput.scss')],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
|
})
|
||||||
|
export class MultiHotkeyInputComponent {
|
||||||
|
constructor (
|
||||||
|
private modal: ModalService,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
ngOnInit () {
|
||||||
|
if (!this.model) {
|
||||||
|
this.model = []
|
||||||
|
}
|
||||||
|
if (typeof this.model == 'string') {
|
||||||
|
this.model = [this.model]
|
||||||
|
}
|
||||||
|
this.model = this.model.map(item => (typeof item == 'string') ? [item] : item)
|
||||||
|
}
|
||||||
|
|
||||||
|
editItem (item) {
|
||||||
|
this.modal.open(HotkeyInputModalComponent).result.then((value: string[]) => {
|
||||||
|
Object.assign(item, value)
|
||||||
|
this.modelChange.emit(this.model)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
addItem () {
|
||||||
|
this.modal.open(HotkeyInputModalComponent).result.then((value: string[]) => {
|
||||||
|
this.model.push(value)
|
||||||
|
this.modelChange.emit(this.model)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
removeItem (item) {
|
||||||
|
this.model = this.model.filter(x => x !== item)
|
||||||
|
this.modelChange.emit(this.model)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Input() model: string[][]
|
||||||
|
@Output() modelChange = new EventEmitter()
|
||||||
|
}
|
10
app/src/settings/components/settingsPane.deep.css
Normal file
10
app/src/settings/components/settingsPane.deep.css
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
:host /deep/ ngb-tabset {
|
||||||
|
flex: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host /deep/ ngb-tabset > .tab-content {
|
||||||
|
padding: 15px 30px;
|
||||||
|
margin: 0;
|
||||||
|
flex: auto;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
button.btn.btn-outline-warning.btn-block(*ngIf='config.restartRequested', '(click)'='restartApp()') Restart the app to apply changes
|
button.btn.btn-outline-warning.btn-block(*ngIf='config.restartRequested', '(click)'='restartApp()') Restart the app to apply changes
|
||||||
|
|
||||||
ngb-tabset(type='tabs')
|
ngb-tabset.vertical(type='tabs')
|
||||||
ngb-tab(*ngFor='let provider of settingsProviders')
|
ngb-tab(*ngFor='let provider of settingsProviders')
|
||||||
template(ngbTabTitle)
|
template(ngbTabTitle)
|
||||||
| {{provider.title}}
|
| {{provider.title}}
|
||||||
@ -134,10 +134,13 @@ ngb-tabset(type='tabs')
|
|||||||
| Hotkeys
|
| Hotkeys
|
||||||
template(ngbTabContent)
|
template(ngbTabContent)
|
||||||
.form-group
|
.form-group
|
||||||
table.table
|
table
|
||||||
tr
|
tr
|
||||||
th Toggle terminal window
|
th Toggle terminal window
|
||||||
td
|
td
|
||||||
hotkey-input('[(model)]'='globalHotkey')
|
hotkey-input('[(model)]'='globalHotkey')
|
||||||
|
tr(*ngFor='let hotkey of hotkeyDescriptions')
|
||||||
|
th {{hotkey.name}}
|
||||||
|
td
|
||||||
|
multi-hotkey-input('[(model)]'='config.store.hotkeys[hotkey.id]')
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
:host {
|
:host {
|
||||||
|
display: flex;
|
||||||
flex: auto;
|
flex: auto;
|
||||||
margin: 15px;
|
|
||||||
|
|
||||||
>.btn-block {
|
>.btn-block {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
@ -2,27 +2,34 @@ import { Component, Inject } from '@angular/core'
|
|||||||
import { ElectronService } from 'services/electron'
|
import { ElectronService } from 'services/electron'
|
||||||
import { ConfigService } from 'services/config'
|
import { ConfigService } from 'services/config'
|
||||||
import { DockingService } from 'services/docking'
|
import { DockingService } from 'services/docking'
|
||||||
|
import { IHotkeyDescription, HotkeyProvider } from 'api/hotkeyProvider'
|
||||||
|
|
||||||
import { BaseTabComponent } from 'components/baseTab'
|
import { BaseTabComponent } from 'components/baseTab'
|
||||||
import { SettingsTab } from '../tab'
|
import { SettingsTab } from '../tab'
|
||||||
import { SettingsProvider } from '../api'
|
import { SettingsTabProvider } from '../api'
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'settings-pane',
|
selector: 'settings-pane',
|
||||||
template: require('./settingsPane.pug'),
|
template: require('./settingsPane.pug'),
|
||||||
styles: [require('./settingsPane.less')],
|
styles: [
|
||||||
|
require('./settingsPane.scss'),
|
||||||
|
require('./settingsPane.deep.css'),
|
||||||
|
],
|
||||||
})
|
})
|
||||||
export class SettingsPaneComponent extends BaseTabComponent<SettingsTab> {
|
export class SettingsPaneComponent extends BaseTabComponent<SettingsTab> {
|
||||||
globalHotkey = ['Ctrl+Shift+G']
|
globalHotkey = ['Ctrl+Shift+G']
|
||||||
|
private hotkeyDescriptions: IHotkeyDescription[]
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public config: ConfigService,
|
public config: ConfigService,
|
||||||
private electron: ElectronService,
|
private electron: ElectronService,
|
||||||
public docking: DockingService,
|
public docking: DockingService,
|
||||||
@Inject(SettingsProvider) public settingsProviders: SettingsProvider[]
|
@Inject(HotkeyProvider) hotkeyProviders: HotkeyProvider[],
|
||||||
|
@Inject(SettingsTabProvider) public settingsProviders: SettingsTabProvider[]
|
||||||
) {
|
) {
|
||||||
super()
|
super()
|
||||||
|
this.hotkeyDescriptions = hotkeyProviders.map(x => x.hotkeys).reduce((a, b) => a.concat(b))
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy () {
|
ngOnDestroy () {
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { Component, Input, ViewContainerRef, ViewChild, ComponentFactoryResolver, ComponentRef } from '@angular/core'
|
import { Component, Input, ViewContainerRef, ViewChild, ComponentFactoryResolver, ComponentRef } from '@angular/core'
|
||||||
import { SettingsProvider } from '../api'
|
import { SettingsTabProvider } from '../api'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'settings-tab-body',
|
selector: 'settings-tab-body',
|
||||||
template: '<template #placeholder></template>',
|
template: '<template #placeholder></template>',
|
||||||
})
|
})
|
||||||
export class SettingsTabBodyComponent {
|
export class SettingsTabBodyComponent {
|
||||||
@Input() provider: SettingsProvider
|
@Input() provider: SettingsTabProvider
|
||||||
@ViewChild('placeholder', {read: ViewContainerRef}) placeholder: ViewContainerRef
|
@ViewChild('placeholder', {read: ViewContainerRef}) placeholder: ViewContainerRef
|
||||||
private component: ComponentRef<Component>
|
private component: ComponentRef<Component>
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ import { HotkeyInputComponent } from './components/hotkeyInput'
|
|||||||
import { HotkeyDisplayComponent } from './components/hotkeyDisplay'
|
import { HotkeyDisplayComponent } from './components/hotkeyDisplay'
|
||||||
import { HotkeyHintComponent } from './components/hotkeyHint'
|
import { HotkeyHintComponent } from './components/hotkeyHint'
|
||||||
import { HotkeyInputModalComponent } from './components/hotkeyInputModal'
|
import { HotkeyInputModalComponent } from './components/hotkeyInputModal'
|
||||||
|
import { MultiHotkeyInputComponent } from './components/multiHotkeyInput'
|
||||||
import { SettingsPaneComponent } from './components/settingsPane'
|
import { SettingsPaneComponent } from './components/settingsPane'
|
||||||
import { SettingsTabBodyComponent } from './components/settingsTabBody'
|
import { SettingsTabBodyComponent } from './components/settingsTabBody'
|
||||||
|
|
||||||
@ -35,6 +36,7 @@ import { RecoveryProvider } from './recoveryProvider'
|
|||||||
HotkeyHintComponent,
|
HotkeyHintComponent,
|
||||||
HotkeyInputComponent,
|
HotkeyInputComponent,
|
||||||
HotkeyInputModalComponent,
|
HotkeyInputModalComponent,
|
||||||
|
MultiHotkeyInputComponent,
|
||||||
SettingsPaneComponent,
|
SettingsPaneComponent,
|
||||||
SettingsTabBodyComponent,
|
SettingsTabBodyComponent,
|
||||||
],
|
],
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Injectable } from '@angular/core'
|
import { Injectable } from '@angular/core'
|
||||||
import { ToolbarButtonProvider, IToolbarButton, AppService } from 'api'
|
import { HotkeysService, ToolbarButtonProvider, IToolbarButton, AppService } from 'api'
|
||||||
import { SessionsService } from './services/sessions'
|
import { SessionsService } from './services/sessions'
|
||||||
import { TerminalTab } from './tab'
|
import { TerminalTab } from './tab'
|
||||||
|
|
||||||
@ -9,8 +9,18 @@ export class ButtonProvider extends ToolbarButtonProvider {
|
|||||||
constructor (
|
constructor (
|
||||||
private app: AppService,
|
private app: AppService,
|
||||||
private sessions: SessionsService,
|
private sessions: SessionsService,
|
||||||
|
hotkeys: HotkeysService,
|
||||||
) {
|
) {
|
||||||
super()
|
super()
|
||||||
|
hotkeys.matchedHotkey.subscribe(async (hotkey) => {
|
||||||
|
if (hotkey == 'new-tab') {
|
||||||
|
this.app.openTab(await this.getNewTab())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async getNewTab (): Promise<TerminalTab> {
|
||||||
|
return new TerminalTab(await this.sessions.createNewSession({ command: 'zsh' }))
|
||||||
}
|
}
|
||||||
|
|
||||||
provide (): IToolbarButton[] {
|
provide (): IToolbarButton[] {
|
||||||
@ -18,8 +28,7 @@ export class ButtonProvider extends ToolbarButtonProvider {
|
|||||||
icon: 'plus',
|
icon: 'plus',
|
||||||
title: 'New terminal',
|
title: 'New terminal',
|
||||||
click: async () => {
|
click: async () => {
|
||||||
let session = await this.sessions.createNewSession({ command: 'zsh' })
|
this.app.openTab(await this.getNewTab())
|
||||||
this.app.openTab(new TerminalTab(session))
|
|
||||||
}
|
}
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
.form-group
|
.form-group
|
||||||
label Preview
|
label Preview
|
||||||
.appearance-preview(
|
.appearance-preview(
|
||||||
[style.font-family]='config.full().appearance.font',
|
[style.font-family]='config.full().terminal.font',
|
||||||
[style.font-size]='config.full().appearance.fontSize + "px"',
|
[style.font-size]='config.full().terminal.fontSize + "px"',
|
||||||
)
|
)
|
||||||
.text john@doe-pc$ ls
|
.text john@doe-pc$ ls
|
||||||
.text foo bar
|
.text foo bar
|
||||||
@ -14,7 +14,7 @@
|
|||||||
input.form-control(
|
input.form-control(
|
||||||
type='text',
|
type='text',
|
||||||
[ngbTypeahead]='fontAutocomplete',
|
[ngbTypeahead]='fontAutocomplete',
|
||||||
'[(ngModel)]'='config.store.appearance.font',
|
'[(ngModel)]'='config.store.terminal.font',
|
||||||
(ngModelChange)='config.save()',
|
(ngModelChange)='config.save()',
|
||||||
)
|
)
|
||||||
small.form-text.text-muted Font to be used in the terminal
|
small.form-text.text-muted Font to be used in the terminal
|
||||||
@ -23,7 +23,7 @@
|
|||||||
label Font size
|
label Font size
|
||||||
input.form-control(
|
input.form-control(
|
||||||
type='number',
|
type='number',
|
||||||
'[(ngModel)]'='config.store.appearance.fontSize',
|
'[(ngModel)]'='config.store.terminal.fontSize',
|
||||||
(ngModelChange)='config.save()',
|
(ngModelChange)='config.save()',
|
||||||
)
|
)
|
||||||
small.form-text.text-muted Text size to be used in the terminal
|
small.form-text.text-muted Text size to be used in the terminal
|
||||||
|
@ -83,8 +83,8 @@ export class TerminalTabComponent extends BaseTabComponent<TerminalTab> {
|
|||||||
|
|
||||||
configure () {
|
configure () {
|
||||||
let config = this.config.full()
|
let config = this.config.full()
|
||||||
preferenceManager.set('font-family', config.appearance.font)
|
preferenceManager.set('font-family', config.terminal.font)
|
||||||
preferenceManager.set('font-size', config.appearance.fontSize)
|
preferenceManager.set('font-size', config.terminal.fontSize)
|
||||||
preferenceManager.set('audible-bell-sound', '')
|
preferenceManager.set('audible-bell-sound', '')
|
||||||
preferenceManager.set('desktop-notification-bell', config.terminal.bell == 'notification')
|
preferenceManager.set('desktop-notification-bell', config.terminal.bell == 'notification')
|
||||||
preferenceManager.set('enable-clipboard-notice', false)
|
preferenceManager.set('enable-clipboard-notice', false)
|
||||||
|
24
app/src/terminal/config.ts
Normal file
24
app/src/terminal/config.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import { ConfigProvider } from 'api'
|
||||||
|
|
||||||
|
|
||||||
|
export class TerminalConfigProvider extends ConfigProvider {
|
||||||
|
defaultConfigValues: any = {
|
||||||
|
terminal: {
|
||||||
|
font: 'monospace',
|
||||||
|
fontSize: 14,
|
||||||
|
bell: 'off',
|
||||||
|
},
|
||||||
|
hotkeys: {
|
||||||
|
'new-tab': [
|
||||||
|
['Ctrl-A', 'C'],
|
||||||
|
['Ctrl-A', 'Ctrl-C'],
|
||||||
|
'Ctrl-Shift-T',
|
||||||
|
]
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
configStructure: any = {
|
||||||
|
terminal: {},
|
||||||
|
hotkeys: {},
|
||||||
|
}
|
||||||
|
}
|
@ -3,8 +3,8 @@ 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 { ToolbarButtonProvider, TabRecoveryProvider } from 'api'
|
import { ToolbarButtonProvider, TabRecoveryProvider, ConfigProvider } from 'api'
|
||||||
import { SettingsProvider } from '../settings/api'
|
import { SettingsTabProvider } from '../settings/api'
|
||||||
|
|
||||||
import { TerminalTabComponent } from './components/terminalTab'
|
import { TerminalTabComponent } from './components/terminalTab'
|
||||||
import { SettingsComponent } from './components/settings'
|
import { SettingsComponent } from './components/settings'
|
||||||
@ -14,6 +14,7 @@ import { ButtonProvider } from './buttonProvider'
|
|||||||
import { RecoveryProvider } from './recoveryProvider'
|
import { RecoveryProvider } from './recoveryProvider'
|
||||||
import { SessionPersistenceProvider } from './api'
|
import { SessionPersistenceProvider } from './api'
|
||||||
import { TerminalSettingsProvider } from './settings'
|
import { TerminalSettingsProvider } from './settings'
|
||||||
|
import { TerminalConfigProvider } from './config'
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
@ -26,7 +27,8 @@ import { TerminalSettingsProvider } from './settings'
|
|||||||
{ provide: TabRecoveryProvider, useClass: RecoveryProvider, multi: true },
|
{ provide: TabRecoveryProvider, useClass: RecoveryProvider, multi: true },
|
||||||
SessionsService,
|
SessionsService,
|
||||||
{ provide: SessionPersistenceProvider, useClass: ScreenPersistenceProvider },
|
{ provide: SessionPersistenceProvider, useClass: ScreenPersistenceProvider },
|
||||||
{ provide: SettingsProvider, useClass: TerminalSettingsProvider, multi: true },
|
{ provide: SettingsTabProvider, useClass: TerminalSettingsProvider, multi: true },
|
||||||
|
{ provide: ConfigProvider, useClass: TerminalConfigProvider, multi: true },
|
||||||
],
|
],
|
||||||
entryComponents: [
|
entryComponents: [
|
||||||
TerminalTabComponent,
|
TerminalTabComponent,
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { Injectable } from '@angular/core'
|
import { Injectable } from '@angular/core'
|
||||||
import { SettingsProvider, ComponentType } from '../settings/api'
|
import { SettingsTabProvider, ComponentType } from '../settings/api'
|
||||||
import { SettingsComponent } from './components/settings'
|
import { SettingsComponent } from './components/settings'
|
||||||
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class TerminalSettingsProvider extends SettingsProvider {
|
export class TerminalSettingsProvider extends SettingsTabProvider {
|
||||||
title = 'Terminal'
|
title = 'Terminal'
|
||||||
|
|
||||||
getComponentType (): ComponentType {
|
getComponentType (): ComponentType {
|
||||||
|
@ -39,7 +39,6 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{ test: /\.css$/, loader: "style-loader!css-loader" },
|
|
||||||
{
|
{
|
||||||
test: /\.less$/,
|
test: /\.less$/,
|
||||||
loader: "style-loader!css-loader!less-loader",
|
loader: "style-loader!css-loader!less-loader",
|
||||||
@ -60,6 +59,16 @@ module.exports = {
|
|||||||
use: ['to-string-loader', 'css-loader', 'sass-loader'],
|
use: ['to-string-loader', 'css-loader', 'sass-loader'],
|
||||||
include: [/app\/.*components\//],
|
include: [/app\/.*components\//],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
test: /\.css$/,
|
||||||
|
use: ['style-loader', 'css-loader', 'sass-loader'],
|
||||||
|
exclude: [/app\/.*components\//],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.css$/,
|
||||||
|
use: ['to-string-loader', 'css-loader'],
|
||||||
|
include: [/app\/.*components\//],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
test: /\.(png|svg)$/,
|
test: /\.(png|svg)$/,
|
||||||
loader: "file-loader",
|
loader: "file-loader",
|
||||||
|
Loading…
Reference in New Issue
Block a user