mirror of
https://github.com/Eugeny/tabby.git
synced 2024-12-22 18:11:43 +03:00
.
This commit is contained in:
parent
e6221ee482
commit
2c2da1d697
@ -1,2 +1,3 @@
|
|||||||
appearance: { }
|
appearance: { }
|
||||||
hotkeys: { }
|
hotkeys: { }
|
||||||
|
terminal: { }
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
appearance:
|
appearance:
|
||||||
font: monospace
|
font: monospace
|
||||||
fontSize: 14
|
fontSize: 14
|
||||||
|
dock: 'off'
|
||||||
|
dockScreen: 'current'
|
||||||
|
dockFill: 50
|
||||||
hotkeys:
|
hotkeys:
|
||||||
new-tab:
|
new-tab:
|
||||||
- ['Ctrl-A', 'C']
|
- ['Ctrl-A', 'C']
|
||||||
@ -48,3 +51,5 @@ hotkeys:
|
|||||||
tab-10:
|
tab-10:
|
||||||
- 'Alt-0'
|
- 'Alt-0'
|
||||||
- ['Ctrl-A', '0']
|
- ['Ctrl-A', '0']
|
||||||
|
terminal:
|
||||||
|
bell: off
|
||||||
|
@ -2,7 +2,6 @@ doctype html
|
|||||||
html
|
html
|
||||||
head
|
head
|
||||||
meta(charset='UTF-8')
|
meta(charset='UTF-8')
|
||||||
title ELEMENTS Benchmark
|
|
||||||
base(href='index.html')
|
base(href='index.html')
|
||||||
script.
|
script.
|
||||||
console.timeStamp('index')
|
console.timeStamp('index')
|
||||||
|
21
app/main.js
21
app/main.js
@ -13,6 +13,10 @@ let windowConfig = new Config({name: 'window'})
|
|||||||
setupWindowManagement = () => {
|
setupWindowManagement = () => {
|
||||||
let windowCloseable
|
let windowCloseable
|
||||||
|
|
||||||
|
app.window.on('show', () => {
|
||||||
|
electron.ipcMain.send('window-shown')
|
||||||
|
})
|
||||||
|
|
||||||
app.window.on('close', (e) => {
|
app.window.on('close', (e) => {
|
||||||
windowConfig.set('windowBoundaries', app.window.getBounds())
|
windowConfig.set('windowBoundaries', app.window.getBounds())
|
||||||
if (!windowCloseable) {
|
if (!windowCloseable) {
|
||||||
@ -33,10 +37,6 @@ setupWindowManagement = () => {
|
|||||||
app.window.focus()
|
app.window.focus()
|
||||||
})
|
})
|
||||||
|
|
||||||
electron.ipcMain.on('window-focus', () => {
|
|
||||||
app.window.focus()
|
|
||||||
})
|
|
||||||
|
|
||||||
electron.ipcMain.on('window-toggle-focus', () => {
|
electron.ipcMain.on('window-toggle-focus', () => {
|
||||||
if (app.window.isFocused()) {
|
if (app.window.isFocused()) {
|
||||||
app.window.minimize()
|
app.window.minimize()
|
||||||
@ -57,6 +57,10 @@ setupWindowManagement = () => {
|
|||||||
app.window.minimize()
|
app.window.minimize()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
electron.ipcMain.on('window-set-bounds', (event, bounds) => {
|
||||||
|
app.window.setBounds(bounds, true)
|
||||||
|
})
|
||||||
|
|
||||||
app.on('before-quit', () => windowCloseable = true)
|
app.on('before-quit', () => windowCloseable = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,7 +73,9 @@ setupMenu = () => {
|
|||||||
{ label: "Quit", accelerator: "CmdOrCtrl+Q", click: () => {
|
{ label: "Quit", accelerator: "CmdOrCtrl+Q", click: () => {
|
||||||
app.window.webContents.send('host:quit-request')
|
app.window.webContents.send('host:quit-request')
|
||||||
}}
|
}}
|
||||||
]}, {
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
label: "Edit",
|
label: "Edit",
|
||||||
submenu: [
|
submenu: [
|
||||||
{ label: "Undo", accelerator: "CmdOrCtrl+Z", selector: "undo:" },
|
{ label: "Undo", accelerator: "CmdOrCtrl+Z", selector: "undo:" },
|
||||||
@ -141,7 +147,12 @@ start = () => {
|
|||||||
app.window.focus()
|
app.window.focus()
|
||||||
|
|
||||||
setupWindowManagement()
|
setupWindowManagement()
|
||||||
|
|
||||||
|
if (platform == 'darwin') {
|
||||||
setupMenu()
|
setupMenu()
|
||||||
|
} else {
|
||||||
|
app.window.setMenu(null)
|
||||||
|
}
|
||||||
|
|
||||||
console.info(`Host startup: ${Date.now() - t0}ms`)
|
console.info(`Host startup: ${Date.now() - t0}ms`)
|
||||||
t0 = Date.now()
|
t0 = Date.now()
|
||||||
|
@ -15,6 +15,7 @@ import { NotifyService } from 'services/notify'
|
|||||||
import { PluginDispatcherService } from 'services/pluginDispatcher'
|
import { PluginDispatcherService } from 'services/pluginDispatcher'
|
||||||
import { QuitterService } from 'services/quitter'
|
import { QuitterService } from 'services/quitter'
|
||||||
import { SessionsService } from 'services/sessions'
|
import { SessionsService } from 'services/sessions'
|
||||||
|
import { DockingService } from 'services/docking'
|
||||||
import { LocalStorageService } from 'angular2-localstorage/LocalStorageEmitter'
|
import { LocalStorageService } from 'angular2-localstorage/LocalStorageEmitter'
|
||||||
|
|
||||||
import { AppComponent } from 'components/app'
|
import { AppComponent } from 'components/app'
|
||||||
@ -37,6 +38,7 @@ import { TerminalComponent } from 'components/terminal'
|
|||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
ConfigService,
|
ConfigService,
|
||||||
|
DockingService,
|
||||||
ElectronService,
|
ElectronService,
|
||||||
HostAppService,
|
HostAppService,
|
||||||
HotkeysService,
|
HotkeysService,
|
||||||
|
@ -1,7 +1,21 @@
|
|||||||
@import "~variables.less";
|
@import "~variables.less";
|
||||||
@import "~mixins.less";
|
|
||||||
|
|
||||||
@title-bg: #0f151b;
|
.button-states() {
|
||||||
|
transition: 0.125s all;
|
||||||
|
border: none;
|
||||||
|
|
||||||
|
&:hover:not(.active) {
|
||||||
|
background: rgba(0, 0, 0, .15);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active:not(.active),
|
||||||
|
&.active {
|
||||||
|
background: rgba(0, 0, 0, .3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@title-bg: #131d27;
|
||||||
|
|
||||||
:host {
|
:host {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -20,11 +34,10 @@
|
|||||||
@tab-border-radius: 4px;
|
@tab-border-radius: 4px;
|
||||||
|
|
||||||
.titlebar {
|
.titlebar {
|
||||||
|
flex: 0 0 @titlebar-height;
|
||||||
|
display: flex;
|
||||||
height: @titlebar-height;
|
height: @titlebar-height;
|
||||||
background: @title-bg;
|
background: @title-bg;
|
||||||
flex: none;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
flex: auto;
|
flex: auto;
|
||||||
@ -34,20 +47,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
flex: none;
|
border: none;
|
||||||
line-height: @titlebar-height - 2px;
|
box-shadow: none;
|
||||||
padding: 0 15px;
|
border-radius: 0;
|
||||||
font-size: 8px;
|
font-size: 8px;
|
||||||
color: #444;
|
|
||||||
|
&:not(:hover):not(:active) {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
transition: 0.25s all;
|
|
||||||
|
|
||||||
.button-states();
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: white;
|
|
||||||
}
|
}
|
||||||
cursor: pointer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-close {
|
.btn-close {
|
||||||
@ -69,19 +76,21 @@
|
|||||||
|
|
||||||
&>button {
|
&>button {
|
||||||
padding: 0 15px;
|
padding: 0 15px;
|
||||||
flex: none;
|
flex: 0 0 auto;
|
||||||
flex-grow: 0;
|
|
||||||
border-bottom: 2px solid transparent;
|
border-bottom: 2px solid transparent;
|
||||||
transition: 0.25s all;
|
transition: 0.25s all;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
|
||||||
.button-states();
|
|
||||||
|
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: #888;
|
color: #888;
|
||||||
|
border: none;
|
||||||
|
border-radius: 0;
|
||||||
|
|
||||||
|
&:not(:hover):not(:active) {
|
||||||
background: @title-bg;
|
background: @title-bg;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&.active-tab-0 .btn-new-tab {
|
&.active-tab-0 .btn-new-tab {
|
||||||
border-bottom-right-radius: @tab-border-radius;
|
border-bottom-right-radius: @tab-border-radius;
|
||||||
@ -98,6 +107,7 @@
|
|||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
background: @body-bg;
|
background: @body-bg;
|
||||||
transition: 0.25s all;
|
transition: 0.25s all;
|
||||||
@ -131,11 +141,9 @@
|
|||||||
button {
|
button {
|
||||||
flex: none;
|
flex: none;
|
||||||
|
|
||||||
border: none;
|
|
||||||
background: transparent;
|
background: transparent;
|
||||||
color: @text-color;
|
color: @text-color;
|
||||||
|
|
||||||
transition: 0.25s all;
|
|
||||||
display: block;
|
display: block;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
|
||||||
@ -150,13 +158,7 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
|
|
||||||
&:hover {
|
.button-states();
|
||||||
background: rgba(255, 255, 255, .05);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
background: rgba(0, 0, 0, .1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover button {
|
&:hover button {
|
||||||
@ -204,6 +206,11 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
|
|
||||||
|
overflow: hidden;
|
||||||
|
&.scrollable {
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
&.active {
|
&.active {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
.titlebar(*ngIf='!config.store.appearance.useNativeFrame')
|
.titlebar(*ngIf='!config.store.appearance.useNativeFrame && config.store.appearance.dock == "off"')
|
||||||
.title((dblclick)='hostApp.maximizeWindow()') Term
|
.title((dblclick)='hostApp.maximizeWindow()') Term
|
||||||
button.btn-minimize((click)='hostApp.minimizeWindow()')
|
button.btn.btn-secondary.btn-minimize((click)='hostApp.minimizeWindow()')
|
||||||
i.fa.fa-window-minimize
|
i.fa.fa-window-minimize
|
||||||
button.btn-maximize((click)='hostApp.maximizeWindow()')
|
button.btn.btn-secondary.btn-maximize((click)='hostApp.maximizeWindow()')
|
||||||
i.fa.fa-window-maximize
|
i.fa.fa-window-maximize
|
||||||
button.btn-close((click)='hostApp.quit()')
|
button.btn.btn-secondary.btn-close((click)='hostApp.quit()')
|
||||||
i.fa.fa-close
|
i.fa.fa-close
|
||||||
|
|
||||||
.tabs(class='active-tab-{{tabs.indexOf(activeTab)}}')
|
.tabs(class='active-tab-{{tabs.indexOf(activeTab)}}')
|
||||||
button.btn-new-tab((click)='newTab()')
|
button.btn.btn-secondary.btn-new-tab((click)='newTab()')
|
||||||
i.fa.fa-plus
|
i.fa.fa-plus
|
||||||
.tab(
|
.tab(
|
||||||
*ngFor='let tab of tabs; let idx = index; trackBy: tab?.id',
|
*ngFor='let tab of tabs; let idx = index; trackBy: tab?.id',
|
||||||
@ -22,11 +22,15 @@
|
|||||||
div.index {{idx + 1}}
|
div.index {{idx + 1}}
|
||||||
div.name {{tab.name || 'Terminal'}}
|
div.name {{tab.name || 'Terminal'}}
|
||||||
button((click)='closeTab(tab)') ×
|
button((click)='closeTab(tab)') ×
|
||||||
button.btn-settings((click)='showSettings()')
|
button.btn.btn-secondary.btn-settings((click)='showSettings()')
|
||||||
i.fa.fa-cog
|
i.fa.fa-cog
|
||||||
|
|
||||||
.tabs-content
|
.tabs-content
|
||||||
.tab(*ngFor='let tab of tabs; trackBy: tab?.id', [class.active]='tab == activeTab')
|
.tab(
|
||||||
|
*ngFor='let tab of tabs; trackBy: tab?.id',
|
||||||
|
[class.active]='tab == activeTab',
|
||||||
|
[class.scrollable]='tab.scrollable',
|
||||||
|
)
|
||||||
terminal(*ngIf='tab.type == "terminal"', [session]='tab.session', '[(title)]'='tab.name')
|
terminal(*ngIf='tab.type == "terminal"', [session]='tab.session', '[(title)]'='tab.name')
|
||||||
settings-pane(*ngIf='tab.type == "settings"')
|
settings-pane(*ngIf='tab.type == "settings"')
|
||||||
|
|
||||||
|
@ -7,10 +7,12 @@ import { HotkeysService } from 'services/hotkeys'
|
|||||||
import { LogService } from 'services/log'
|
import { LogService } from 'services/log'
|
||||||
import { QuitterService } from 'services/quitter'
|
import { QuitterService } from 'services/quitter'
|
||||||
import { ConfigService } from 'services/config'
|
import { ConfigService } from 'services/config'
|
||||||
|
import { DockingService } from 'services/docking'
|
||||||
import { Session, SessionsService } from 'services/sessions'
|
import { Session, SessionsService } from 'services/sessions'
|
||||||
|
|
||||||
import 'angular2-toaster/lib/toaster.css'
|
import 'angular2-toaster/lib/toaster.css'
|
||||||
import 'global.less'
|
import 'global.less'
|
||||||
|
import 'theme.scss'
|
||||||
|
|
||||||
|
|
||||||
const TYPE_TERMINAL = 'terminal'
|
const TYPE_TERMINAL = 'terminal'
|
||||||
@ -19,6 +21,7 @@ const TYPE_SETTINGS = 'settings'
|
|||||||
class Tab {
|
class Tab {
|
||||||
id: number
|
id: number
|
||||||
name: string
|
name: string
|
||||||
|
scrollable: boolean
|
||||||
static lastTabID = 0
|
static lastTabID = 0
|
||||||
|
|
||||||
constructor (public type: string, public session: Session) {
|
constructor (public type: string, public session: Session) {
|
||||||
@ -62,6 +65,7 @@ export class AppComponent {
|
|||||||
constructor(
|
constructor(
|
||||||
private elementRef: ElementRef,
|
private elementRef: ElementRef,
|
||||||
private sessions: SessionsService,
|
private sessions: SessionsService,
|
||||||
|
private docking: DockingService,
|
||||||
public hostApp: HostAppService,
|
public hostApp: HostAppService,
|
||||||
public hotkeys: HotkeysService,
|
public hotkeys: HotkeysService,
|
||||||
public config: ConfigService,
|
public config: ConfigService,
|
||||||
@ -126,6 +130,11 @@ export class AppComponent {
|
|||||||
this.hotkeys.globalHotkey.subscribe(() => {
|
this.hotkeys.globalHotkey.subscribe(() => {
|
||||||
this.hostApp.toggleWindow()
|
this.hostApp.toggleWindow()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
this.docking.dock()
|
||||||
|
this.hostApp.shown.subscribe(() => {
|
||||||
|
this.docking.dock()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
newTab () {
|
newTab () {
|
||||||
@ -192,18 +201,17 @@ export class AppComponent {
|
|||||||
this.addTerminalTab(session)
|
this.addTerminalTab(session)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
this.newTab()
|
// this.newTab()
|
||||||
|
this.showSettings();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy () {
|
|
||||||
}
|
|
||||||
|
|
||||||
showSettings() {
|
showSettings() {
|
||||||
let settingsTab = this.tabs.find((x) => x.type == TYPE_SETTINGS)
|
let settingsTab = this.tabs.find((x) => x.type == TYPE_SETTINGS)
|
||||||
if (!settingsTab) {
|
if (!settingsTab) {
|
||||||
settingsTab = new Tab(TYPE_SETTINGS, null)
|
settingsTab = new Tab(TYPE_SETTINGS, null)
|
||||||
|
settingsTab.scrollable = true
|
||||||
this.tabs.push(settingsTab)
|
this.tabs.push(settingsTab)
|
||||||
}
|
}
|
||||||
this.selectTab(settingsTab)
|
this.selectTab(settingsTab)
|
||||||
|
@ -46,7 +46,7 @@ export class HotkeyHintComponent {
|
|||||||
this.setMatches(partialMatches)
|
this.setMatches(partialMatches)
|
||||||
|
|
||||||
if (this.keyTimeoutInterval == null) {
|
if (this.keyTimeoutInterval == null) {
|
||||||
this.keyTimeoutInterval = setInterval(() => {
|
this.keyTimeoutInterval = window.setInterval(() => {
|
||||||
if (this.hotkeys.getCurrentPartiallyMatchedHotkeys().length == 0) {
|
if (this.hotkeys.getCurrentPartiallyMatchedHotkeys().length == 0) {
|
||||||
clearInterval(this.keyTimeoutInterval)
|
clearInterval(this.keyTimeoutInterval)
|
||||||
this.keyTimeoutInterval = null
|
this.keyTimeoutInterval = null
|
||||||
|
@ -35,7 +35,7 @@ export class HotkeyInputModalComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit () {
|
ngOnInit () {
|
||||||
this.keyTimeoutInterval = setInterval(() => {
|
this.keyTimeoutInterval = window.setInterval(() => {
|
||||||
if (!this.lastKeyEvent) {
|
if (!this.lastKeyEvent) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,19 @@
|
|||||||
:host {
|
:host {
|
||||||
overflow-y: auto;
|
>.btn-block {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
>.modal-body {
|
>.modal-body {
|
||||||
padding: 0 0 20px !important;
|
padding: 0 0 20px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.appearance-preview {
|
||||||
|
background: black;
|
||||||
|
padding: 10px 20px;
|
||||||
|
margin: 0 0 10px;
|
||||||
|
|
||||||
|
.text {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,36 +1,165 @@
|
|||||||
.restart-bar(*ngIf='restartRequested')
|
button.btn.btn-outline-warning.btn-block(*ngIf='restartRequested', '(click)'='restartApp()') Restart the app to apply changes
|
||||||
button.btn.btn-default.pull-right('(click)'='restartApp()') Restart
|
|
||||||
| Restart the app to apply changes
|
|
||||||
|
|
||||||
ngb-tabset(type='tabs')
|
ngb-tabset(type='tabs')
|
||||||
ngb-tab
|
ngb-tab
|
||||||
template(ngbTabTitle)
|
template(ngbTabTitle)
|
||||||
| General
|
| Application
|
||||||
template(ngbTabContent)
|
template(ngbTabContent)
|
||||||
.form-group
|
.form-group
|
||||||
label.form-control
|
label Window frame
|
||||||
input(
|
br
|
||||||
type='checkbox',
|
div(
|
||||||
'[(ngModel)]'='config.store.appearance.useNativeFrame',
|
'[(ngModel)]'='config.store.appearance.useNativeFrame'
|
||||||
'(ngModelChange)'='config.save(); requestRestart()',
|
'(ngModelChange)'='config.save(); requestRestart()'
|
||||||
|
ngbRadioGroup
|
||||||
)
|
)
|
||||||
| Use native window frame
|
label.btn.btn-secondary
|
||||||
|
input(
|
||||||
|
type='radio',
|
||||||
|
[value]='true'
|
||||||
|
)
|
||||||
|
| Native
|
||||||
|
label.btn.btn-secondary
|
||||||
|
input(
|
||||||
|
type='radio',
|
||||||
|
[value]='false'
|
||||||
|
)
|
||||||
|
| Custom
|
||||||
|
small.form-text.text-muted Whether a custom window or an OS native window should be used
|
||||||
|
|
||||||
.form-group
|
.form-group
|
||||||
label.control-label Font
|
label Dock the terminal
|
||||||
|
br
|
||||||
|
.row
|
||||||
|
.col-auto
|
||||||
|
div(
|
||||||
|
'[(ngModel)]'='config.store.appearance.dock'
|
||||||
|
'(ngModelChange)'='config.save(); docking.dock()'
|
||||||
|
ngbRadioGroup
|
||||||
|
)
|
||||||
|
label.btn.btn-secondary
|
||||||
|
input(
|
||||||
|
type='radio',
|
||||||
|
[value]='"off"'
|
||||||
|
)
|
||||||
|
| Off
|
||||||
|
label.btn.btn-secondary
|
||||||
|
input(
|
||||||
|
type='radio',
|
||||||
|
[value]='"top"'
|
||||||
|
)
|
||||||
|
| Top
|
||||||
|
label.btn.btn-secondary
|
||||||
|
input(
|
||||||
|
type='radio',
|
||||||
|
[value]='"left"'
|
||||||
|
)
|
||||||
|
| Left
|
||||||
|
label.btn.btn-secondary
|
||||||
|
input(
|
||||||
|
type='radio',
|
||||||
|
[value]='"right"'
|
||||||
|
)
|
||||||
|
| Right
|
||||||
|
label.btn.btn-secondary
|
||||||
|
input(
|
||||||
|
type='radio',
|
||||||
|
[value]='"bottom"'
|
||||||
|
)
|
||||||
|
| Bottom
|
||||||
|
.col
|
||||||
|
input(
|
||||||
|
type='range',
|
||||||
|
'[(ngModel)]'='config.store.appearance.dockFill',
|
||||||
|
'(ngModelChange)'='config.save(); docking.dock()',
|
||||||
|
min='1',
|
||||||
|
max='100',
|
||||||
|
step='1'
|
||||||
|
)
|
||||||
|
br
|
||||||
|
div(
|
||||||
|
*ngIf='config.store.appearance.dock != "off"',
|
||||||
|
'[(ngModel)]'='config.store.appearance.dockScreen'
|
||||||
|
'(ngModelChange)'='config.save(); docking.dock()'
|
||||||
|
ngbRadioGroup
|
||||||
|
)
|
||||||
|
label.btn.btn-secondary
|
||||||
|
input(
|
||||||
|
type='radio',
|
||||||
|
[value]='"current"'
|
||||||
|
)
|
||||||
|
| Current
|
||||||
|
label.btn.btn-secondary(*ngFor='let screen of docking.getScreens()')
|
||||||
|
input(
|
||||||
|
type='radio',
|
||||||
|
[value]='screen.id'
|
||||||
|
)
|
||||||
|
| {{screen.name}}
|
||||||
|
|
||||||
|
ngb-tab
|
||||||
|
template(ngbTabTitle)
|
||||||
|
| Appearance
|
||||||
|
template(ngbTabContent)
|
||||||
|
.row
|
||||||
|
.col-sm-6
|
||||||
|
.form-group
|
||||||
|
label Preview
|
||||||
|
.appearance-preview(
|
||||||
|
[style.font-family]='config.store.appearance.font',
|
||||||
|
[style.font-size]='config.store.appearance.fontSize + "px"',
|
||||||
|
)
|
||||||
|
.text john@doe-pc$ ls
|
||||||
|
.text foo bar
|
||||||
|
.col-sm-6
|
||||||
|
.form-group
|
||||||
|
label Font
|
||||||
input.form-control(
|
input.form-control(
|
||||||
type='text',
|
type='text',
|
||||||
[ngbTypeahead]='fontAutocomplete',
|
[ngbTypeahead]='fontAutocomplete',
|
||||||
'[(ngModel)]'='config.store.appearance.font',
|
'[(ngModel)]'='config.store.appearance.font',
|
||||||
'(ngModelChange)'='config.save()',
|
'(ngModelChange)'='config.save()',
|
||||||
)
|
)
|
||||||
|
small.form-text.text-muted Font to be used in the terminal
|
||||||
|
|
||||||
.form-group
|
.form-group
|
||||||
label.control-label Font size
|
label Font size
|
||||||
input.form-control(
|
input.form-control(
|
||||||
type='number',
|
type='number',
|
||||||
'[(ngModel)]'='config.store.appearance.fontSize',
|
'[(ngModel)]'='config.store.appearance.fontSize',
|
||||||
'(ngModelChange)'='config.save()',
|
'(ngModelChange)'='config.save()',
|
||||||
)
|
)
|
||||||
|
small.form-text.text-muted Text size to be used in the terminal
|
||||||
|
|
||||||
|
ngb-tab
|
||||||
|
template(ngbTabTitle)
|
||||||
|
| Terminal
|
||||||
|
template(ngbTabContent)
|
||||||
|
.form-group
|
||||||
|
label Terminal bell
|
||||||
|
br
|
||||||
|
div(
|
||||||
|
'[(ngModel)]'='config.store.terminal.bell'
|
||||||
|
'(ngModelChange)'='config.save()'
|
||||||
|
ngbRadioGroup
|
||||||
|
)
|
||||||
|
label.btn.btn-secondary
|
||||||
|
input(
|
||||||
|
type='radio',
|
||||||
|
[value]='"off"'
|
||||||
|
)
|
||||||
|
| Off
|
||||||
|
label.btn.btn-secondary
|
||||||
|
input(
|
||||||
|
type='radio',
|
||||||
|
[value]='"sound"'
|
||||||
|
)
|
||||||
|
| Sound
|
||||||
|
label.btn.btn-secondary
|
||||||
|
input(
|
||||||
|
type='radio',
|
||||||
|
[value]='"notification"'
|
||||||
|
)
|
||||||
|
| Notification
|
||||||
|
|
||||||
ngb-tab
|
ngb-tab
|
||||||
template(ngbTabTitle)
|
template(ngbTabTitle)
|
||||||
|
@ -2,6 +2,7 @@ import { Component } from '@angular/core'
|
|||||||
import { ElectronService } from 'services/electron'
|
import { ElectronService } from 'services/electron'
|
||||||
import { HostAppService, PLATFORM_WINDOWS, PLATFORM_LINUX, PLATFORM_MAC } from 'services/hostApp'
|
import { HostAppService, PLATFORM_WINDOWS, PLATFORM_LINUX, PLATFORM_MAC } from 'services/hostApp'
|
||||||
import { ConfigService } from 'services/config'
|
import { ConfigService } from 'services/config'
|
||||||
|
import { DockingService } from 'services/docking'
|
||||||
import { Observable } from 'rxjs/Observable'
|
import { Observable } from 'rxjs/Observable'
|
||||||
import 'rxjs/add/operator/map'
|
import 'rxjs/add/operator/map'
|
||||||
import 'rxjs/add/operator/debounceTime'
|
import 'rxjs/add/operator/debounceTime'
|
||||||
@ -27,6 +28,7 @@ export class SettingsPaneComponent {
|
|||||||
constructor(
|
constructor(
|
||||||
public config: ConfigService,
|
public config: ConfigService,
|
||||||
private electron: ElectronService,
|
private electron: ElectronService,
|
||||||
|
public docking: DockingService,
|
||||||
hostApp: HostAppService,
|
hostApp: HostAppService,
|
||||||
) {
|
) {
|
||||||
this.isWindows = hostApp.platform == PLATFORM_WINDOWS
|
this.isWindows = hostApp.platform == PLATFORM_WINDOWS
|
||||||
|
@ -110,8 +110,11 @@ export class TerminalComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
configure () {
|
configure () {
|
||||||
preferenceManager.set('font-family', this.config.full().appearance.font)
|
let config = this.config.full()
|
||||||
preferenceManager.set('font-size', this.config.full().appearance.fontSize)
|
preferenceManager.set('font-family', config.appearance.font)
|
||||||
|
preferenceManager.set('font-size', config.appearance.fontSize)
|
||||||
|
preferenceManager.set('audible-bell-sound', '')
|
||||||
|
preferenceManager.set('desktop-notification-bell', config.terminal.bell == 'notification')
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy () {
|
ngOnDestroy () {
|
||||||
|
@ -1,16 +1,6 @@
|
|||||||
@import "~variables.less";
|
@import "~variables.less";
|
||||||
@import "~mixins.less";
|
@import "~mixins.less";
|
||||||
|
|
||||||
* {
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
font-family: @font-family;
|
|
||||||
font-size: @font-size;
|
|
||||||
color: @text-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
html.platform-win32 {
|
html.platform-win32 {
|
||||||
body.focused {
|
body.focused {
|
||||||
@ -23,6 +13,7 @@ body {
|
|||||||
transition: 0.5s border;
|
transition: 0.5s border;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
|
cursor: default;
|
||||||
}
|
}
|
||||||
|
|
||||||
.no-drag, a, button, checkbox, .form-control, #toast-container {
|
.no-drag, a, button, checkbox, .form-control, #toast-container {
|
||||||
@ -91,46 +82,6 @@ ngb-modal-window.fade.in {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ngb-tabset {
|
|
||||||
>ul.nav-tabs {
|
|
||||||
border-bottom: none;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
background: rgba(0,0,0,.25);
|
|
||||||
display: flex;
|
|
||||||
align-items: start;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
|
|
||||||
.nav-item {
|
|
||||||
flex: none;
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
.nav-link {
|
|
||||||
background: transparent;
|
|
||||||
border: none;
|
|
||||||
padding: 10px 15px;
|
|
||||||
color: @text-color;
|
|
||||||
text-decoration: none;
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
background: rgba(0,0,0,.5);
|
|
||||||
border-bottom: 1px solid #777;
|
|
||||||
}
|
|
||||||
|
|
||||||
i {
|
|
||||||
display: block;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 18px;
|
|
||||||
margin: 0 0 5px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
>.tab-content {
|
|
||||||
padding: 10px 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.btn {
|
.btn {
|
||||||
@ -163,33 +114,6 @@ ngb-typeahead-window {
|
|||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
-webkit-appearance: none;
|
-webkit-appearance: none;
|
||||||
border-bottom: 1px solid @dark-border;
|
//border-bottom: 1px solid @dark-border;
|
||||||
.list-group-item-style();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.list-group-item {
|
|
||||||
.list-group-item-style();
|
|
||||||
}
|
|
||||||
|
|
||||||
label.control-label {
|
|
||||||
background: rgba(0, 0, 0, .4);
|
|
||||||
color: #aaa;
|
|
||||||
font-size: 10px;
|
|
||||||
display: block;
|
|
||||||
margin: 0;
|
|
||||||
padding: 5px 10px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-control {
|
|
||||||
-webkit-user-select: initial;
|
|
||||||
background: rgba(0, 0, 0, .4);
|
|
||||||
display: block;
|
|
||||||
margin: 0 0 5px;
|
|
||||||
width: 100%;
|
|
||||||
border: none;
|
|
||||||
height: 30px;
|
|
||||||
line-height: 30px;
|
|
||||||
color: #ccc;
|
|
||||||
padding: 0 10px;
|
|
||||||
}
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import * as fs from 'fs'
|
import * as fs from 'fs'
|
||||||
import { ElectronService } from 'services/electron'
|
import { ElectronService } from 'services/electron'
|
||||||
|
|
||||||
|
const debounceDelay = 500
|
||||||
|
|
||||||
abstract class Handler {
|
abstract class Handler {
|
||||||
constructor (protected plugin) { }
|
constructor (protected plugin) { }
|
||||||
@ -48,16 +49,31 @@ export default class HyperlinksPlugin {
|
|||||||
const oldDeleteChars = terminal.screen_.constructor.prototype.deleteChars
|
const oldDeleteChars = terminal.screen_.constructor.prototype.deleteChars
|
||||||
terminal.screen_.insertString = (...args) => {
|
terminal.screen_.insertString = (...args) => {
|
||||||
let ret = oldInsertString.bind(terminal.screen_)(...args)
|
let ret = oldInsertString.bind(terminal.screen_)(...args)
|
||||||
this.insertLinks(terminal.screen_)
|
this.debounceInsertLinks(terminal.screen_)
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
terminal.screen_.deleteChars = (...args) => {
|
terminal.screen_.deleteChars = (...args) => {
|
||||||
let ret = oldDeleteChars.bind(terminal.screen_)(...args)
|
let ret = oldDeleteChars.bind(terminal.screen_)(...args)
|
||||||
this.insertLinks(terminal.screen_)
|
this.debounceInsertLinks(terminal.screen_)
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debounceInsertLinks (screen) {
|
||||||
|
if (screen.__insertLinksTimeout) {
|
||||||
|
screen.__insertLinksRebounce = true
|
||||||
|
} else {
|
||||||
|
screen.__insertLinksTimeout = window.setTimeout(() => {
|
||||||
|
this.insertLinks(screen)
|
||||||
|
screen.__insertLinksTimeout = null
|
||||||
|
if (screen.__insertLinksRebounce) {
|
||||||
|
screen.__insertLinksRebounce = false
|
||||||
|
this.debounceInsertLinks(screen)
|
||||||
|
}
|
||||||
|
}, debounceDelay)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
insertLinks (screen) {
|
insertLinks (screen) {
|
||||||
const traverse = (parentNode: Node) => {
|
const traverse = (parentNode: Node) => {
|
||||||
Array.from(parentNode.childNodes).forEach((node) => {
|
Array.from(parentNode.childNodes).forEach((node) => {
|
||||||
|
@ -9,13 +9,21 @@ const defaultConfigValues : IConfigData = require('../../defaultConfigValues.yam
|
|||||||
const defaultConfigStructure : IConfigData = require('../../defaultConfigStructure.yaml')
|
const defaultConfigStructure : IConfigData = require('../../defaultConfigStructure.yaml')
|
||||||
|
|
||||||
export interface IAppearanceData {
|
export interface IAppearanceData {
|
||||||
|
useNativeFrame: boolean
|
||||||
font: string
|
font: string
|
||||||
fontSize: number
|
fontSize: number
|
||||||
|
dock: string
|
||||||
|
dockScreen: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ITerminalData {
|
||||||
|
bell: string|boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IConfigData {
|
export interface IConfigData {
|
||||||
appearance?: IAppearanceData
|
appearance?: IAppearanceData
|
||||||
hotkeys?: any
|
hotkeys?: any
|
||||||
|
terminal?: ITerminalData
|
||||||
}
|
}
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
71
app/src/services/docking.ts
Normal file
71
app/src/services/docking.ts
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
import { Injectable } from '@angular/core'
|
||||||
|
import { HostAppService } from 'services/hostApp'
|
||||||
|
import { ConfigService } from 'services/config'
|
||||||
|
import { ElectronService } from 'services/electron'
|
||||||
|
|
||||||
|
|
||||||
|
export interface IScreen {
|
||||||
|
id: string
|
||||||
|
name: string
|
||||||
|
}
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class DockingService {
|
||||||
|
constructor(
|
||||||
|
private electron: ElectronService,
|
||||||
|
private config: ConfigService,
|
||||||
|
private hostApp: HostAppService,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
dock () {
|
||||||
|
let display = this.electron.screen.getAllDisplays()
|
||||||
|
.filter((x) => x.id == this.config.full().appearance.dockScreen)[0]
|
||||||
|
if (!display) {
|
||||||
|
display = this.getCurrentScreen()
|
||||||
|
}
|
||||||
|
|
||||||
|
let dockSide = this.config.full().appearance.dock
|
||||||
|
let newBounds: Electron.Rectangle = { x: 0, y: 0, width: 0, height: 0 }
|
||||||
|
let fill = 0.5
|
||||||
|
|
||||||
|
if (dockSide == 'off') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (dockSide == 'left' || dockSide == 'right') {
|
||||||
|
newBounds.width = fill * display.bounds.width
|
||||||
|
newBounds.height = display.bounds.height
|
||||||
|
}
|
||||||
|
if (dockSide == 'top' || dockSide == 'bottom') {
|
||||||
|
newBounds.width = display.bounds.width
|
||||||
|
newBounds.height = fill * display.bounds.height
|
||||||
|
}
|
||||||
|
if (dockSide == 'right') {
|
||||||
|
newBounds.x = display.bounds.x + display.bounds.width * (1.0 - fill)
|
||||||
|
} else {
|
||||||
|
newBounds.x = display.bounds.x
|
||||||
|
}
|
||||||
|
if (dockSide == 'bottom') {
|
||||||
|
newBounds.y = display.bounds.y + display.bounds.height * (1.0 - fill)
|
||||||
|
} else {
|
||||||
|
newBounds.y = display.bounds.y
|
||||||
|
}
|
||||||
|
|
||||||
|
this.hostApp.setBounds(newBounds)
|
||||||
|
}
|
||||||
|
|
||||||
|
getCurrentScreen () {
|
||||||
|
return this.electron.screen.getDisplayNearestPoint(this.electron.screen.getCursorScreenPoint())
|
||||||
|
}
|
||||||
|
|
||||||
|
getScreens () {
|
||||||
|
return this.electron.screen.getAllDisplays().map((display, index) => {
|
||||||
|
return {
|
||||||
|
id: display.id,
|
||||||
|
name: {
|
||||||
|
0: 'Primary display',
|
||||||
|
1: 'Secondary display',
|
||||||
|
}[index] || `Display ${index + 1}`
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -15,6 +15,7 @@ export class ElectronService {
|
|||||||
this.electron = require('electron')
|
this.electron = require('electron')
|
||||||
this.remoteElectron = this.remoteRequire('electron')
|
this.remoteElectron = this.remoteRequire('electron')
|
||||||
this.app = this.remoteElectron.app
|
this.app = this.remoteElectron.app
|
||||||
|
this.screen = this.remoteElectron.screen
|
||||||
this.dialog = this.remoteElectron.dialog
|
this.dialog = this.remoteElectron.dialog
|
||||||
this.shell = this.electron.shell
|
this.shell = this.electron.shell
|
||||||
this.clipboard = this.electron.clipboard
|
this.clipboard = this.electron.clipboard
|
||||||
@ -36,6 +37,7 @@ export class ElectronService {
|
|||||||
dialog: any
|
dialog: any
|
||||||
clipboard: any
|
clipboard: any
|
||||||
globalShortcut: any
|
globalShortcut: any
|
||||||
|
screen: any
|
||||||
private electron: any
|
private electron: any
|
||||||
private remoteElectron: any
|
private remoteElectron: any
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,10 @@ export class HostAppService {
|
|||||||
console.error('Unhandled exception:', err)
|
console.error('Unhandled exception:', err)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
electron.ipcRenderer.on('window-shown', () => {
|
||||||
|
this.shown.emit()
|
||||||
|
})
|
||||||
|
|
||||||
this.ready.subscribe(() => {
|
this.ready.subscribe(() => {
|
||||||
electron.ipcRenderer.send('app:ready')
|
electron.ipcRenderer.send('app:ready')
|
||||||
})
|
})
|
||||||
@ -31,6 +35,7 @@ export class HostAppService {
|
|||||||
platform: string;
|
platform: string;
|
||||||
quitRequested = new EventEmitter<any>()
|
quitRequested = new EventEmitter<any>()
|
||||||
ready = new EventEmitter<any>()
|
ready = new EventEmitter<any>()
|
||||||
|
shown = new EventEmitter<any>()
|
||||||
|
|
||||||
private logger: Logger;
|
private logger: Logger;
|
||||||
|
|
||||||
@ -74,6 +79,10 @@ export class HostAppService {
|
|||||||
this.electron.ipcRenderer.send('window-maximize')
|
this.electron.ipcRenderer.send('window-maximize')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setBounds (bounds: Electron.Rectangle) {
|
||||||
|
this.electron.ipcRenderer.send('window-set-bounds', bounds)
|
||||||
|
}
|
||||||
|
|
||||||
quit () {
|
quit () {
|
||||||
this.logger.info('Quitting')
|
this.logger.info('Quitting')
|
||||||
this.electron.app.quit()
|
this.electron.app.quit()
|
||||||
|
65
app/src/theme.scss
Normal file
65
app/src/theme.scss
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
$white: #fff !default;
|
||||||
|
$black: #000 !default;
|
||||||
|
$red: #d9534f !default;
|
||||||
|
$orange: #f0ad4e !default;
|
||||||
|
$yellow: #ffd500 !default;
|
||||||
|
$green: #5cb85c !default;
|
||||||
|
$blue: #0275d8 !default;
|
||||||
|
$teal: #5bc0de !default;
|
||||||
|
$pink: #ff5b77 !default;
|
||||||
|
$purple: #613d7c !default;
|
||||||
|
|
||||||
|
|
||||||
|
$body-bg: #1D272D;
|
||||||
|
$body-bg2: #131d27;
|
||||||
|
$body-color: #aaa;
|
||||||
|
$font-family-sans-serif: "Source Sans Pro";
|
||||||
|
$font-size-base: 14rem / 16;
|
||||||
|
|
||||||
|
$btn-secondary-color: #ccc;
|
||||||
|
$btn-secondary-bg: #222;
|
||||||
|
$btn-secondary-border: #444;
|
||||||
|
|
||||||
|
//$btn-warning-bg: rgba($orange, .5);
|
||||||
|
|
||||||
|
|
||||||
|
$nav-tabs-border-color: $body-bg2;
|
||||||
|
$nav-tabs-border-width: 1px;
|
||||||
|
$nav-tabs-border-radius: 0;
|
||||||
|
$nav-tabs-link-hover-border-color: $body-bg2;
|
||||||
|
$nav-tabs-active-link-hover-color: $body-color;
|
||||||
|
$nav-tabs-active-link-hover-bg: #424f56;
|
||||||
|
$nav-tabs-active-link-hover-border-color: $body-bg2;
|
||||||
|
|
||||||
|
$input-bg: #111;
|
||||||
|
$input-bg-disabled: #333;
|
||||||
|
|
||||||
|
$input-color: $body-color;
|
||||||
|
//$input-border-color: rgba($black,.15);
|
||||||
|
//$input-box-shadow: inset 0 1px 1px rgba($black,.075);
|
||||||
|
|
||||||
|
$input-border-radius: 0;
|
||||||
|
|
||||||
|
$input-bg-focus: $input-bg;
|
||||||
|
//$input-border-focus: lighten($brand-primary, 25%);
|
||||||
|
//$input-box-shadow-focus: $input-box-shadow, rgba($input-border-focus, .6);
|
||||||
|
$input-color-focus: $input-color;
|
||||||
|
|
||||||
|
|
||||||
|
@import '~bootstrap/scss/bootstrap.scss';
|
||||||
|
|
||||||
|
.nav-tabs {
|
||||||
|
background: $btn-secondary-bg;
|
||||||
|
.nav-link {
|
||||||
|
transition: 0.25s all;
|
||||||
|
border-bottom-color: $nav-tabs-border-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngb-tabset .tab-content {
|
||||||
|
padding-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
[ngbradiogroup] > label.active {
|
||||||
|
background: $blue;
|
||||||
|
}
|
@ -2,7 +2,9 @@
|
|||||||
"name": "term",
|
"name": "term",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"apply-loader": "^0.1.0",
|
"apply-loader": "^0.1.0",
|
||||||
|
"autoprefixer": "^6.7.7",
|
||||||
"awesome-typescript-loader": "3.0.8",
|
"awesome-typescript-loader": "3.0.8",
|
||||||
|
"bootstrap": "^4.0.0-alpha.6",
|
||||||
"css-loader": "0.26.1",
|
"css-loader": "0.26.1",
|
||||||
"dataurl": "^0.1.0",
|
"dataurl": "^0.1.0",
|
||||||
"electron": "^1.4.13",
|
"electron": "^1.4.13",
|
||||||
@ -16,10 +18,12 @@
|
|||||||
"less": "^2.7.1",
|
"less": "^2.7.1",
|
||||||
"less-loader": "^2.2.3",
|
"less-loader": "^2.2.3",
|
||||||
"node-gyp": "^3.4.0",
|
"node-gyp": "^3.4.0",
|
||||||
|
"node-sass": "^4.5.0",
|
||||||
"pug-html-loader": "^1.0.9",
|
"pug-html-loader": "^1.0.9",
|
||||||
"pug-loader": "^2.3.0",
|
"pug-loader": "^2.3.0",
|
||||||
"pug-static-loader": "0.0.1",
|
"pug-static-loader": "0.0.1",
|
||||||
"raw-loader": "^0.5.1",
|
"raw-loader": "^0.5.1",
|
||||||
|
"sass-loader": "^6.0.3",
|
||||||
"style-loader": "^0.13.1",
|
"style-loader": "^0.13.1",
|
||||||
"to-string-loader": "^1.1.5",
|
"to-string-loader": "^1.1.5",
|
||||||
"tslint": "4.2.0",
|
"tslint": "4.2.0",
|
||||||
|
@ -50,6 +50,10 @@ module.exports = {
|
|||||||
loader: "to-string-loader!css-loader!less-loader",
|
loader: "to-string-loader!css-loader!less-loader",
|
||||||
include: [/app\/src\/components\//],
|
include: [/app\/src\/components\//],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
test: /\.scss$/,
|
||||||
|
use: ['style-loader', 'css-loader', 'sass-loader']
|
||||||
|
},
|
||||||
{
|
{
|
||||||
test: /\.(png|svg)$/,
|
test: /\.(png|svg)$/,
|
||||||
loader: "file-loader",
|
loader: "file-loader",
|
||||||
|
Loading…
Reference in New Issue
Block a user