diff --git a/.gitignore b/.gitignore index 8b64a9bf..15daa358 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ npm-debug.log # other .next +.DS_Store diff --git a/app/assets/icons.svg b/app/assets/icons.svg new file mode 100644 index 00000000..482a666b --- /dev/null +++ b/app/assets/icons.svg @@ -0,0 +1,8 @@ + + + + close + + + + diff --git a/app/css/hyperterm.css b/app/css/hyperterm.css index 66537281..25be425e 100644 --- a/app/css/hyperterm.css +++ b/app/css/hyperterm.css @@ -85,3 +85,10 @@ header { opacity: 1; pointer-events: inherit; } + +.icon { + vertical-align: middle; + fill: currentColor; + width: 1em; + height: 1em; +} diff --git a/app/css/tabs.css b/app/css/tabs.css index c82ad987..86978bfe 100644 --- a/app/css/tabs.css +++ b/app/css/tabs.css @@ -32,17 +32,18 @@ nav { list-style-type: none; flex-grow: 1; text-align: center; + position: relative; } .tabs li.is_active { color: #fff; - position: relative; } .tabs li span { + transition: color .2s ease; display: block; - border-left: 1px solid transparent; - border-right: 1px solid transparent; + border-left: 1px solid transparent; + border-right: 1px solid transparent; } .tabs li.is_active span { @@ -64,10 +65,54 @@ nav { bottom: -1px; } -.tabs li:not(.is_active):hover { +.tabs li:not(.is_active):hover span { color: #ccc; } .tabs li.has_activity, .tabs li.has_activity:hover { color: #50E3C2; } + +/* The close button */ + +.tabs li i { + transition: opacity .2s ease, + color .2s ease, + transform .25s ease, + background-color .1s ease; + pointer-events: none; + position: absolute; + right: 7px; + top: 7px; + display: inline-block; + width: 14px; + height: 14px; + border-radius: 100%; + color: #e9e9e9; + opacity: 0; + transform: scale(.95); +} + +.tabs li:hover i { + opacity: 1; + transform: none; + pointer-events: all; +} + +.tabs li i:hover { + background-color: rgba(255,255,255, .13); + color: #fff; +} + +.tabs li i:active { + background-color: rgba(255,255,255, .1); + color: #909090; +} + +.tabs li i .icon { + position: absolute; + left: 4px; + top: 4px; + width: 6px; + height: 6px; +} diff --git a/app/hyperterm.js b/app/hyperterm.js index ce12d205..8365907b 100644 --- a/app/hyperterm.js +++ b/app/hyperterm.js @@ -44,6 +44,7 @@ export default class HyperTerm extends Component { this.focusActive = this.focusActive.bind(this); this.closeBrowser = this.closeBrowser.bind(this); this.onHeaderMouseDown = this.onHeaderMouseDown.bind(this); + this.closeTab = this.closeTab.bind(this); this.moveLeft = this.moveLeft.bind(this); this.moveRight = this.moveRight.bind(this); @@ -64,6 +65,7 @@ export default class HyperTerm extends Component { return null != title ? title : 'Shell'; })} onChange={this.onChange} + onClose={this.closeTab} /> @@ -113,11 +115,15 @@ export default class HyperTerm extends Component { this.rpc.emit('new', { cols: this.state.cols, rows: this.state.rows }); } - closeTab () { + closeActiveTab () { + this.closeTab(this.state.active); + } + + closeTab (id) { if (this.state.sessions.length) { - const uid = this.state.sessions[this.state.active]; + const uid = this.state.sessions[id]; this.rpc.emit('exit', { uid }); - this.onSessionExit(uid); + this.onSessionExit({ uid }); } } @@ -226,7 +232,7 @@ export default class HyperTerm extends Component { }); this.rpc.on('new tab', this.requestTab.bind(this)); - this.rpc.on('close tab', this.closeTab.bind(this)); + this.rpc.on('close tab', this.closeActiveTab.bind(this)); this.rpc.on('title', this.onRemoteTitle.bind(this)); this.rpc.on('move left', this.moveLeft); diff --git a/app/tabs.js b/app/tabs.js index 11335564..f33e00e0 100644 --- a/app/tabs.js +++ b/app/tabs.js @@ -1,7 +1,7 @@ import React from 'react'; import classes from 'classnames'; -export default function ({ data = [], active, activeMarkers = {}, onChange }) { +export default function ({ data = [], active, activeMarkers = [], onChange, onClose }) { return