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