Eugene Pankov 9 năm trước cách đây
mục cha
commit
4e451d0598

+ 1 - 1
app/index.pug

@@ -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

+ 3 - 3
app/main.js

@@ -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',

+ 85 - 83
app/src/components/app.less

@@ -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;
-
-    background: @navbar-default-bg;
-    :host.platform-darwin & {
-        background: fade(@navbar-default-bg, 50%);
-    }
+    height: @tabs-height;
 
-    .navbar-btn-big {
-        margin: 0;
-        padding: 15px 20px 15px;
-        background-color: #333;
-        text-align: left;
+    display: flex;
+    flex-direction: row;
 
-        background: transparent;
-        box-shadow: none;
+    .btn-new-tab, .tab {
+        line-height: @tabs-height - 2px;
+        cursor: pointer;
+    }
 
-        &.btn-profile {
-            padding: 7px 14px 7px;
-            display: flex;
-            flex-direction: row;
-            max-width: 150px;
+    .btn-new-tab {
+        padding: 0 15px;
+        flex: none;
+        flex-grow: 0;
+        border-bottom: 2px solid transparent;
+        transition: 0.25s all;
 
-            :host.platform-darwin & {
-                max-width: 120px;
-            }
+        text-transform: uppercase;
+        font-weight: bold;
+        color: #888;
 
-            >img {
-                flex: none;
-                float: left;
-                margin: 2px 10px 4px 0;
-                width: 30px;
-                height: 30px;
+        i {
+            margin-right: 10px;
+        }
 
-                :host.platform-darwin & {
-                    margin-right: 0;
-                }
-            }
+        &:hover {
+            background: rgba(255, 255, 255, .1);
+        }
 
-            >div {
-                flex: auto;
+        &:active {
+            background: rgba(0, 0, 0, .1);
+        }
+    }
 
-                :host.platform-darwin & {
-                    display: none;
-                }
+    .tab {
+        flex: auto;
+        flex-basis: 0;
+        flex-grow: 1;
 
-                .username {
-                }
+        display: flex;
+        flex-direction: row;
 
-                .settings {
-                    font-size: 10px;
-                }
-            }
+        div {
+            flex: auto;
+            padding: 0 15px;
         }
 
-        &.btn-close {
-            font-size: 38px;
-            padding: 1px 13px 2px;
-            line-height: 47px;
+        border-bottom: 2px solid transparent;
+        transition: 0.25s all;
 
-            :host.platform-darwin & {
-                display: none;
-            }
+        &:hover:not(.active) {
+            background: rgba(255, 255, 255, .05);
         }
-    }
 
-    button.navbar-btn-big:hover {
-        background-color: #222;
-    }
+        &:active {
+            background: rgba(0, 0, 0, .1);
+        }
 
-    button.navbar-btn-big:active {
-        background-color: #111;
-    }
+        &.active {
+            background: #141c23;
+            border-bottom: 2px solid #69bbea;
+        }
+
+        button {
+            flex: none;
 
+            border: none;
+            background: transparent;
+            opacity: 0;
+            transition: 0.25s all;
 
-    .navbar-brand {
-        padding: 11px 15px;
-        width: 150px;
+            @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;
 
-footer {
-  display: block;
-  flex: none;
-  height: 1px;
-}
+        &.active {
+            display: flex;
 
-perfect-scrollbar {
-    flex: auto;
-    min-height: 0;
+            >* {
+                flex: auto;
+            }
+        }
+    }
 }

+ 10 - 15
app/src/components/app.pug

@@ -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)

+ 26 - 6
app/src/components/app.ts

@@ -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)
+    }
+
+    selectTab (tab) {
+        this.activeTab = tab
     }
 
-    closeTab (session) {
-        session.destroy()
+    closeTab (tab) {
+        tab.session.destroy()
+        this.tabs = this.tabs.filter((x) => x != tab)
+        this.selectTab(this.tabs[0])
     }
 
     ngOnInit () {
+        this.newTab()
     }
 
     ngOnDestroy () {

+ 27 - 6
app/src/components/terminal.ts

@@ -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)
             }
         }

+ 1 - 0
app/src/services/sessions.ts

@@ -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,

+ 2 - 1
tsconfig.json

@@ -15,7 +15,8 @@
     },
     "compileOnSave": false,
     "exclude": [
-        "node_modules"
+        "node_modules",
+        "platforms",
     ],
     "files": [
         "app/src/app.d.ts",