mirror of
https://github.com/Eugeny/tabby
synced 2024-11-14 08:57:21 +00:00
.
This commit is contained in:
parent
8a02fd1708
commit
4e451d0598
8 changed files with 160 additions and 120 deletions
|
@ -9,5 +9,5 @@ html
|
|||
window.nodeRequire = require
|
||||
script(src='./preload.js')
|
||||
script(src='./bundle.js', defer)
|
||||
body(style='background-image: radial-gradient(circle, #2b3840 0%, #1D272D 100%); min-height: 100vh')
|
||||
body(style='background: ; min-height: 100vh')
|
||||
app
|
||||
|
|
|
@ -75,10 +75,10 @@ start = () => {
|
|||
let options = {
|
||||
width: 800,
|
||||
height: 400,
|
||||
icon: `${app.getAppPath()}/assets/img/icon.png`,
|
||||
//icon: `${app.getAppPath()}/assets/img/icon.png`,
|
||||
title: 'ELEMENTS Benchmark',
|
||||
minWidth: 800,
|
||||
minHeight: 400,
|
||||
minWidth: 300,
|
||||
minHeight: 100,
|
||||
'web-preferences': {'web-security': false},
|
||||
//- background to avoid the flash of unstyled window
|
||||
backgroundColor: '#1D272D',
|
||||
|
|
|
@ -12,121 +12,123 @@
|
|||
background: @body-bg;
|
||||
}
|
||||
|
||||
@tabs-height: 40px;
|
||||
|
||||
.navbar {
|
||||
.tabs {
|
||||
flex: none;
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
border-top: none;
|
||||
-webkit-app-region: drag;
|
||||
margin: 0;
|
||||
height: @tabs-height;
|
||||
|
||||
background: @navbar-default-bg;
|
||||
:host.platform-darwin & {
|
||||
background: fade(@navbar-default-bg, 50%);
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
.btn-new-tab, .tab {
|
||||
line-height: @tabs-height - 2px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.navbar-btn-big {
|
||||
margin: 0;
|
||||
padding: 15px 20px 15px;
|
||||
background-color: #333;
|
||||
text-align: left;
|
||||
.btn-new-tab {
|
||||
padding: 0 15px;
|
||||
flex: none;
|
||||
flex-grow: 0;
|
||||
border-bottom: 2px solid transparent;
|
||||
transition: 0.25s all;
|
||||
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
text-transform: uppercase;
|
||||
font-weight: bold;
|
||||
color: #888;
|
||||
|
||||
&.btn-profile {
|
||||
padding: 7px 14px 7px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
max-width: 150px;
|
||||
|
||||
:host.platform-darwin & {
|
||||
max-width: 120px;
|
||||
}
|
||||
|
||||
>img {
|
||||
flex: none;
|
||||
float: left;
|
||||
margin: 2px 10px 4px 0;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
|
||||
:host.platform-darwin & {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
>div {
|
||||
flex: auto;
|
||||
|
||||
:host.platform-darwin & {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.username {
|
||||
}
|
||||
|
||||
.settings {
|
||||
font-size: 10px;
|
||||
}
|
||||
}
|
||||
i {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
&.btn-close {
|
||||
font-size: 38px;
|
||||
padding: 1px 13px 2px;
|
||||
line-height: 47px;
|
||||
&:hover {
|
||||
background: rgba(255, 255, 255, .1);
|
||||
}
|
||||
|
||||
:host.platform-darwin & {
|
||||
display: none;
|
||||
}
|
||||
&:active {
|
||||
background: rgba(0, 0, 0, .1);
|
||||
}
|
||||
}
|
||||
|
||||
button.navbar-btn-big:hover {
|
||||
background-color: #222;
|
||||
}
|
||||
.tab {
|
||||
flex: auto;
|
||||
flex-basis: 0;
|
||||
flex-grow: 1;
|
||||
|
||||
button.navbar-btn-big:active {
|
||||
background-color: #111;
|
||||
}
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
div {
|
||||
flex: auto;
|
||||
padding: 0 15px;
|
||||
}
|
||||
|
||||
.navbar-brand {
|
||||
padding: 11px 15px;
|
||||
width: 150px;
|
||||
border-bottom: 2px solid transparent;
|
||||
transition: 0.25s all;
|
||||
|
||||
&:hover:not(.active) {
|
||||
background: rgba(255, 255, 255, .05);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background: rgba(0, 0, 0, .1);
|
||||
}
|
||||
|
||||
&.active {
|
||||
background: #141c23;
|
||||
border-bottom: 2px solid #69bbea;
|
||||
}
|
||||
|
||||
button {
|
||||
flex: none;
|
||||
|
||||
border: none;
|
||||
background: transparent;
|
||||
opacity: 0;
|
||||
transition: 0.25s all;
|
||||
|
||||
@button-size: @tabs-height * 0.6;
|
||||
width: @button-size;
|
||||
height: @button-size;
|
||||
border-radius: @button-size / 2;
|
||||
line-height: @button-size * 0.8;
|
||||
margin-top: (@tabs-height - @button-size) * 0.4;
|
||||
margin-right: 10px;
|
||||
|
||||
:host.platform-darwin & {
|
||||
display: block;
|
||||
margin: auto;
|
||||
float: none;
|
||||
text-align: center;
|
||||
font-size: 20px;
|
||||
|
||||
&:hover {
|
||||
background: rgba(255, 255, 255, .05);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background: rgba(0, 0, 0, .1);
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
height: 28px;
|
||||
&:hover button {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[scrollable] {
|
||||
width: 100vw;
|
||||
.tabs-content {
|
||||
flex: auto;
|
||||
display: flex;
|
||||
|
||||
.nano {
|
||||
.tab {
|
||||
display: none;
|
||||
flex: auto;
|
||||
height: auto;
|
||||
position: relative;
|
||||
|
||||
&.active {
|
||||
display: flex;
|
||||
|
||||
>* {
|
||||
flex: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
footer {
|
||||
display: block;
|
||||
flex: none;
|
||||
height: 1px;
|
||||
}
|
||||
|
||||
perfect-scrollbar {
|
||||
flex: auto;
|
||||
min-height: 0;
|
||||
}
|
||||
|
|
|
@ -1,19 +1,14 @@
|
|||
div.navbar.navbar-default.draggable
|
||||
button.btn.btn-default.navbar-btn.navbar-btn-big.btn-close.pull-right((click)='hide()', title='Hide')
|
||||
| ×
|
||||
button.btn.btn-default.navbar-btn.navbar-btn-big.pull-right((click)='showSettings()', title='Settings')
|
||||
i.fa.fa-cog
|
||||
.tabs
|
||||
.tab(*ngFor='let tab of tabs; trackBy: tab?.id', (click)='selectTab(tab)', [class.active]='tab == activeTab')
|
||||
div {{tab.name}}
|
||||
button((click)='closeTab(tab)') ×
|
||||
.btn-new-tab((click)='newTab()')
|
||||
i.fa.fa-plus
|
||||
span Tab
|
||||
|
||||
ngb-tabset
|
||||
ngb-tab(*ngFor='let tab of tabs; trackBy: tab?.name')
|
||||
template(ngbTabTitle)
|
||||
span {{tab.name}}
|
||||
button.btn.btn-default((click)='closeTab(tab)') ×
|
||||
template(ngbTabContent)
|
||||
terminal([session]='tab', style='width: 300px; height: 300px;')
|
||||
|
||||
button.btn.btn-default((click)='newTab()') New tab
|
||||
footer
|
||||
.tabs-content
|
||||
.tab(*ngFor='let tab of tabs; trackBy: tab?.id', [class.active]='tab == activeTab')
|
||||
terminal([session]='tab.session', '[(title)]'='tab.name')
|
||||
|
||||
toaster-container([toasterconfig]="toasterconfig")
|
||||
template(ngbModalContainer)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Component, ElementRef } from '@angular/core'
|
||||
import { Component } from '@angular/core'
|
||||
import { ModalService } from 'services/modal'
|
||||
import { ElectronService } from 'services/electron'
|
||||
import { HostAppService } from 'services/hostApp'
|
||||
|
@ -13,6 +13,17 @@ import 'angular2-toaster/lib/toaster.css'
|
|||
import 'global.less'
|
||||
|
||||
|
||||
class Tab {
|
||||
id: number
|
||||
name: string
|
||||
static lastTabID = 0
|
||||
|
||||
constructor (public session: Session) {
|
||||
this.id = Tab.lastTabID++
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app',
|
||||
template: require('./app.pug'),
|
||||
|
@ -24,7 +35,6 @@ export class AppComponent {
|
|||
private modal: ModalService,
|
||||
private electron: ElectronService,
|
||||
private sessions: SessionsService,
|
||||
element: ElementRef,
|
||||
log: LogService,
|
||||
_quitter: QuitterService,
|
||||
) {
|
||||
|
@ -41,17 +51,27 @@ export class AppComponent {
|
|||
}
|
||||
|
||||
toasterConfig: ToasterConfig
|
||||
tabs: Session[] = []
|
||||
tabs: Tab[] = []
|
||||
activeTab: Tab
|
||||
|
||||
newTab () {
|
||||
this.tabs.push(this.sessions.createSession({command: 'zsh'}))
|
||||
const tab = new Tab(this.sessions.createSession({command: 'bash'}))
|
||||
this.tabs.push(tab)
|
||||
this.selectTab(tab)
|
||||
}
|
||||
|
||||
closeTab (session) {
|
||||
session.destroy()
|
||||
selectTab (tab) {
|
||||
this.activeTab = tab
|
||||
}
|
||||
|
||||
closeTab (tab) {
|
||||
tab.session.destroy()
|
||||
this.tabs = this.tabs.filter((x) => x != tab)
|
||||
this.selectTab(this.tabs[0])
|
||||
}
|
||||
|
||||
ngOnInit () {
|
||||
this.newTab()
|
||||
}
|
||||
|
||||
ngOnDestroy () {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Component, Input, ElementRef } from '@angular/core'
|
||||
import { Component, NgZone, Input, Output, EventEmitter, ElementRef } from '@angular/core'
|
||||
import { ElectronService } from 'services/electron'
|
||||
import { ConfigService } from 'services/config'
|
||||
|
||||
|
@ -7,6 +7,19 @@ import { Session } from 'services/sessions'
|
|||
const hterm = require('hterm-commonjs')
|
||||
|
||||
|
||||
hterm.hterm.VT.ESC['k'] = function(parseState) {
|
||||
parseState.resetArguments();
|
||||
|
||||
function parseOSC(parseState) {
|
||||
if (!this.parseUntilStringTerminator_(parseState) || parseState.func == parseOSC) {
|
||||
return
|
||||
}
|
||||
|
||||
this.terminal.setWindowTitle(parseState.args[0])
|
||||
}
|
||||
parseState.func = parseOSC
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'terminal',
|
||||
template: '',
|
||||
|
@ -14,9 +27,12 @@ const hterm = require('hterm-commonjs')
|
|||
})
|
||||
export class TerminalComponent {
|
||||
@Input() session: Session
|
||||
title: string
|
||||
@Output() titleChange = new EventEmitter()
|
||||
private terminal: any
|
||||
|
||||
constructor(
|
||||
private zone: NgZone,
|
||||
private electron: ElectronService,
|
||||
private elementRef: ElementRef,
|
||||
public config: ConfigService,
|
||||
|
@ -27,23 +43,28 @@ export class TerminalComponent {
|
|||
let io
|
||||
hterm.hterm.defaultStorage = new hterm.lib.Storage.Memory()
|
||||
this.terminal = new hterm.hterm.Terminal()
|
||||
this.terminal.setWindowTitle = (title) => {
|
||||
this.zone.run(() => {
|
||||
this.title = title
|
||||
this.titleChange.emit(title)
|
||||
})
|
||||
}
|
||||
this.terminal.onTerminalReady = () => {
|
||||
this.terminal.installKeyboard()
|
||||
io = this.terminal.io.push()
|
||||
const dataSubscription = this.session.dataAvailable.subscribe((data) => {
|
||||
io.writeUTF8(data)
|
||||
io.writeUTF16(data)
|
||||
})
|
||||
const closedSubscription = this.session.closed.subscribe(() => {
|
||||
dataSubscription.unsubscribe()
|
||||
closedSubscription.unsubscribe()
|
||||
})
|
||||
io.onVTKeystroke = (str) => {
|
||||
this.session.write(str)
|
||||
}
|
||||
io.sendString = (str) => {
|
||||
|
||||
io.onVTKeystroke = io.sendString = (str) => {
|
||||
this.session.write(str)
|
||||
}
|
||||
io.onTerminalResize = (columns, rows) => {
|
||||
console.log(`Resizing to ${columns}x${rows}`)
|
||||
this.session.resize(columns, rows)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ export class Session {
|
|||
this.name = options.name
|
||||
this.pty = ptyjs.spawn('sh', ['-c', options.command], {
|
||||
name: 'xterm-color',
|
||||
//name: 'screen-256color',
|
||||
cols: 80,
|
||||
rows: 30,
|
||||
cwd: options.cwd || process.env.HOME,
|
||||
|
|
|
@ -15,7 +15,8 @@
|
|||
},
|
||||
"compileOnSave": false,
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
"node_modules",
|
||||
"platforms",
|
||||
],
|
||||
"files": [
|
||||
"app/src/app.d.ts",
|
||||
|
|
Loading…
Reference in a new issue