Add text resize feature, and change font of console screen to Hack.
This commit is contained in:
@@ -13,10 +13,12 @@ Major dependencies includes:
|
||||
- [Babel](https://babeljs.io/), Licensed under MIT license
|
||||
- [XTerm.js](https://xtermjs.org/), Licensed under MIT license
|
||||
- [normalize.css](https://github.com/necolas/normalize.css), Licensed under MIT license
|
||||
- [Roboto font](https://en.wikipedia.org/wiki/Roboto), Licensed under Apache license.
|
||||
- [Roboto font](https://en.wikipedia.org/wiki/Roboto), Licensed under Apache license
|
||||
Packaged by [Christian Hoffmeister](https://github.com/choffmeister/roboto-fontface-bower), Licensed under Apache 2.0
|
||||
- [iconv-lite](https://github.com/ashtuchkin/iconv-lite), Licensed under MIT license
|
||||
- [buffer](https://github.com/feross/buffer), Licensed under MIT license
|
||||
- [Hack font](https://github.com/source-foundry/Hack), [View license](https://github.com/source-foundry/Hack/blob/master/LICENSE.md)
|
||||
- [fontfaceobserver](https://github.com/bramstein/fontfaceobserver), [View license](https://github.com/bramstein/fontfaceobserver/blob/master/LICENSE)
|
||||
|
||||
## For back-end application
|
||||
|
||||
|
||||
12
package-lock.json
generated
12
package-lock.json
generated
@@ -6522,6 +6522,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"fontfaceobserver": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fontfaceobserver/-/fontfaceobserver-2.1.0.tgz",
|
||||
"integrity": "sha512-ReOsO2F66jUa0jmv2nlM/s1MiutJx/srhAe2+TE8dJCMi02ZZOcCTxTCQFr3Yet+uODUtnr4Mewg+tNQ+4V1Ng==",
|
||||
"dev": true
|
||||
},
|
||||
"for-each": {
|
||||
"version": "0.3.3",
|
||||
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
|
||||
@@ -7505,6 +7511,12 @@
|
||||
"integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==",
|
||||
"dev": true
|
||||
},
|
||||
"hack-font": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/hack-font/-/hack-font-3.3.0.tgz",
|
||||
"integrity": "sha512-RohrcAr3UaKiIoxDlOytCjObcUAucfFc6V5fKu6gBrvmvTfIXeBqZwR0Q5kb9qpbluThJWt326LClLKIGiFyug==",
|
||||
"dev": true
|
||||
},
|
||||
"har-schema": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
"eslint-plugin-prettier": "^3.1.1",
|
||||
"eslint-plugin-vue": "^5.2.3",
|
||||
"file-loader": "^4.3.0",
|
||||
"fontfaceobserver": "^2.1.0",
|
||||
"hack-font": "^3.3.0",
|
||||
"html-loader": "^0.5.5",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"iconv-lite": "^0.5.0",
|
||||
|
||||
@@ -285,6 +285,14 @@ body {
|
||||
box-shadow: 1px 1px 0 2px #0003;
|
||||
}
|
||||
|
||||
.icon.icon-keyboardkey2 {
|
||||
background: #fff;
|
||||
color: #999;
|
||||
padding: 4px 6px;
|
||||
display: inline-block;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
/* Windows */
|
||||
.window {
|
||||
position: absolute;
|
||||
|
||||
30
ui/home.css
30
ui/home.css
@@ -369,6 +369,16 @@
|
||||
flex-direction: column;
|
||||
color: #fff;
|
||||
font-size: 1.2em;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#home-content-preload-drop {
|
||||
height: 0px;
|
||||
width: 0px;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
@@ -377,26 +387,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
#home-content > .screen {
|
||||
display: flex;
|
||||
justify-content: top;
|
||||
flex-direction: column;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
#home-content > .screen > .screen-error {
|
||||
display: block;
|
||||
padding: 10px;
|
||||
background: #b44;
|
||||
color: #fff;
|
||||
font-size: 0.75em;
|
||||
flex: 0 0;
|
||||
}
|
||||
|
||||
#home-content > .screen > .screen-screen {
|
||||
flex: auto;
|
||||
}
|
||||
|
||||
#home-content-wrap {
|
||||
max-width: 520px;
|
||||
margin: 50px auto;
|
||||
|
||||
33
ui/home.vue
33
ui/home.vue
@@ -62,6 +62,8 @@
|
||||
:screen="tab.current"
|
||||
:screens="tab.tabs"
|
||||
@stopped="tabStopped"
|
||||
@warning="tabWarning"
|
||||
@info="tabInfo"
|
||||
@updated="tabUpdated"
|
||||
>
|
||||
<div id="home-content-wrap">
|
||||
@@ -102,6 +104,8 @@
|
||||
>.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div id="home-content-preload-drop"></div>
|
||||
</screens>
|
||||
|
||||
<connect-widget
|
||||
@@ -468,7 +472,8 @@ export default {
|
||||
control: data.control,
|
||||
toolbar: false,
|
||||
indicator: {
|
||||
error: "",
|
||||
level: "",
|
||||
message: "",
|
||||
updated: false
|
||||
},
|
||||
status: {
|
||||
@@ -520,10 +525,30 @@ export default {
|
||||
this.$emit("tab-closed", this.tab.tabs);
|
||||
},
|
||||
tabStopped(index, reason) {
|
||||
if (reason === null) {
|
||||
this.tab.tabs[index].indicator.error = "";
|
||||
if (reason !== null) {
|
||||
this.tab.tabs[index].indicator.message = "" + reason;
|
||||
this.tab.tabs[index].indicator.level = "error";
|
||||
} else {
|
||||
this.tab.tabs[index].indicator.error = "" + reason;
|
||||
this.tab.tabs[index].indicator.message = "";
|
||||
this.tab.tabs[index].indicator.level = "";
|
||||
}
|
||||
},
|
||||
tabWarning(index, msg) {
|
||||
if (msg.length > 0) {
|
||||
this.tab.tabs[index].indicator.message = msg;
|
||||
this.tab.tabs[index].indicator.level = "warning";
|
||||
} else {
|
||||
this.tab.tabs[index].indicator.message = "";
|
||||
this.tab.tabs[index].indicator.level = "";
|
||||
}
|
||||
},
|
||||
tabInfo(index, msg) {
|
||||
if (msg.length > 0) {
|
||||
this.tab.tabs[index].indicator.message = msg;
|
||||
this.tab.tabs[index].indicator.level = "info";
|
||||
} else {
|
||||
this.tab.tabs[index].indicator.message = "";
|
||||
this.tab.tabs[index].indicator.level = "";
|
||||
}
|
||||
},
|
||||
tabUpdated(index) {
|
||||
|
||||
@@ -19,6 +19,18 @@
|
||||
|
||||
@charset "utf-8";
|
||||
|
||||
@import "~hack-font/build/web/hack.css";
|
||||
|
||||
#home-content > #home-content-preload-drop::before {
|
||||
content: " ";
|
||||
font-family: Hack, monospace;
|
||||
font-weight: bold;
|
||||
}
|
||||
#home-content > #home-content-preload-drop::after {
|
||||
content: " ";
|
||||
font-family: Hack, monospace;
|
||||
}
|
||||
|
||||
#home-content > .screen > .screen-screen > .screen-console {
|
||||
position: relative;
|
||||
}
|
||||
@@ -132,4 +144,5 @@
|
||||
}
|
||||
|
||||
#home-content > .screen > .screen-screen > .screen-console > .console-console {
|
||||
font-family: Hack, monospace;
|
||||
}
|
||||
|
||||
@@ -39,6 +39,23 @@
|
||||
>
|
||||
<h2 style="display:none;">Tool bar</h2>
|
||||
|
||||
<div class="console-toolbar-item">
|
||||
<h3 class="tb-title">Text size</h3>
|
||||
|
||||
<ul class="hlst lst-nostyle">
|
||||
<li>
|
||||
<a class="tb-item" href="javascript:;" @click="fontSizeUp">
|
||||
<span class="tb-key-icon icon icon-keyboardkey2">Increase +</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="tb-item" href="javascript:;" @click="fontSizeDown">
|
||||
<span class="tb-key-icon icon icon-keyboardkey2">Decrease -</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-for="(keyType, keyTypeIdx) in screenKeys"
|
||||
:key="keyTypeIdx"
|
||||
@@ -62,6 +79,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import FontFaceObserver from "fontfaceobserver";
|
||||
import { Terminal } from "xterm";
|
||||
import { WebLinksAddon } from "xterm-addon-web-links";
|
||||
import { FitAddon } from "xterm-addon-fit";
|
||||
@@ -71,15 +89,25 @@ import { consoleScreenKeys } from "./screen_console_keys.js";
|
||||
import "./screen_console.css";
|
||||
import "xterm/css/xterm.css";
|
||||
|
||||
const termTypeFace = "Hack";
|
||||
const termFallbackTypeFace = "monospace";
|
||||
const termTypeFaceLoadTimeout = 10000;
|
||||
const termDefaultFontSize = 16;
|
||||
const termMinFontSize = 14;
|
||||
const termMaxFontSize = 36;
|
||||
|
||||
class Term {
|
||||
constructor(control) {
|
||||
const resizeDelayInterval = 500;
|
||||
|
||||
this.closed = false;
|
||||
this.fontSize = termDefaultFontSize;
|
||||
this.term = new Terminal({
|
||||
allowTransparency: false,
|
||||
cursorBlink: true,
|
||||
cursorStyle: "block",
|
||||
fontFamily: termTypeFace + ", " + termFallbackTypeFace,
|
||||
fontSize: this.fontSize,
|
||||
logLevel: process.env.NODE_ENV === "development" ? "info" : "off"
|
||||
});
|
||||
this.fit = new FitAddon();
|
||||
@@ -177,7 +205,7 @@ class Term {
|
||||
});
|
||||
}
|
||||
|
||||
init(root, callbacks) {
|
||||
open(root, callbacks) {
|
||||
this.term.open(root);
|
||||
|
||||
this.term.textarea.addEventListener("focus", callbacks.focus);
|
||||
@@ -220,6 +248,32 @@ class Term {
|
||||
this.refit();
|
||||
}
|
||||
|
||||
init(root, callbacks) {
|
||||
const self = this;
|
||||
|
||||
return Promise.all([
|
||||
new FontFaceObserver(termTypeFace).load(null, termTypeFaceLoadTimeout),
|
||||
new FontFaceObserver(termTypeFace, { weight: "bold" }).load(
|
||||
null,
|
||||
termTypeFaceLoadTimeout
|
||||
)
|
||||
])
|
||||
.then(() => {
|
||||
self.open(root, callbacks);
|
||||
})
|
||||
.catch(() => {
|
||||
callbacks.warn(
|
||||
"Unable to load remote font, using " +
|
||||
termFallbackTypeFace +
|
||||
" instead"
|
||||
);
|
||||
|
||||
self.term.setOption("fontFamily", termFallbackTypeFace);
|
||||
|
||||
self.open(root, callbacks);
|
||||
});
|
||||
}
|
||||
|
||||
dispatch(event) {
|
||||
try {
|
||||
this.term.textarea.dispatchEvent(event);
|
||||
@@ -244,6 +298,26 @@ class Term {
|
||||
}
|
||||
}
|
||||
|
||||
fontSizeUp() {
|
||||
if (this.fontSize >= termMaxFontSize) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.fontSize += 2;
|
||||
this.term.setOption("fontSize", this.fontSize);
|
||||
this.refit();
|
||||
}
|
||||
|
||||
fontSizeDown() {
|
||||
if (this.fontSize <= termMinFontSize) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.fontSize -= 2;
|
||||
this.term.setOption("fontSize", this.fontSize);
|
||||
this.refit();
|
||||
}
|
||||
|
||||
focus() {
|
||||
try {
|
||||
this.term.focus();
|
||||
@@ -332,8 +406,8 @@ export default {
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
async mounted() {
|
||||
await this.init();
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.deinit();
|
||||
@@ -342,10 +416,12 @@ export default {
|
||||
triggerActive() {
|
||||
this.active ? this.activate() : this.deactivate();
|
||||
},
|
||||
init() {
|
||||
async init() {
|
||||
let self = this;
|
||||
|
||||
this.term.init(this.$el.getElementsByClassName("console-console")[0], {
|
||||
await this.term.init(
|
||||
this.$el.getElementsByClassName("console-console")[0],
|
||||
{
|
||||
focus(e) {
|
||||
document.addEventListener("keyup", self.localKeypress);
|
||||
document.addEventListener("keydown", self.localKeypress);
|
||||
@@ -353,8 +429,15 @@ export default {
|
||||
blur(e) {
|
||||
document.removeEventListener("keyup", self.localKeypress);
|
||||
document.removeEventListener("keydown", self.localKeypress);
|
||||
},
|
||||
warn(msg) {
|
||||
self.$emit("warning", msg);
|
||||
},
|
||||
info(msg) {
|
||||
self.$emit("info", msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
this.triggerActive();
|
||||
this.runRunner();
|
||||
@@ -421,6 +504,12 @@ export default {
|
||||
|
||||
this.term.dispatch(new KeyboardEvent("keydown", key));
|
||||
this.term.dispatch(new KeyboardEvent("keyup", key));
|
||||
},
|
||||
fontSizeUp() {
|
||||
this.term.fontSizeUp();
|
||||
},
|
||||
fontSizeDown() {
|
||||
this.term.fontSizeDown();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
52
ui/widgets/screens.css
Normal file
52
ui/widgets/screens.css
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
// Sshwifty - A Web SSH client
|
||||
//
|
||||
// Copyright (C) 2019 Rui NI <nirui@gmx.com>
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
@charset "utf-8";
|
||||
|
||||
#home-content > .screen {
|
||||
display: flex;
|
||||
justify-content: top;
|
||||
flex-direction: column;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
#home-content > .screen > .screen-error {
|
||||
display: block;
|
||||
padding: 10px;
|
||||
background: #b44;
|
||||
color: #fff;
|
||||
font-size: 0.75em;
|
||||
flex: 0 0;
|
||||
}
|
||||
|
||||
#home-content > .screen > .screen-error.screen-error-level-error {
|
||||
background: #b44;
|
||||
}
|
||||
|
||||
#home-content > .screen > .screen-error.screen-error-level-warning {
|
||||
background: #b82;
|
||||
}
|
||||
|
||||
#home-content > .screen > .screen-error.screen-error-level-info {
|
||||
background: #28b;
|
||||
}
|
||||
|
||||
#home-content > .screen > .screen-screen {
|
||||
flex: auto;
|
||||
}
|
||||
@@ -30,8 +30,12 @@
|
||||
>
|
||||
<h1 style="display:none;">Main Interface</h1>
|
||||
|
||||
<div v-if="screenInfo.indicator.error.length > 0" class="screen-error">
|
||||
{{ screenInfo.indicator.error }}
|
||||
<div
|
||||
v-if="screenInfo.indicator.message.length > 0"
|
||||
class="screen-error"
|
||||
:class="'screen-error-level-' + screenInfo.indicator.level"
|
||||
>
|
||||
{{ screenInfo.indicator.message }}
|
||||
</div>
|
||||
|
||||
<div class="screen-screen" style="position: relative">
|
||||
@@ -44,6 +48,8 @@
|
||||
:style="'background-color: ' + screenInfo.control.activeColor()"
|
||||
style="top: 0; right: 0; left: 0; bottom: 0; padding: 0; margin: 0; position: absolute; overflow: hidden"
|
||||
@stopped="stopped(idx, $event)"
|
||||
@warning="warning(idx, $event)"
|
||||
@info="info(idx, $event)"
|
||||
@updated="updated(idx)"
|
||||
></component>
|
||||
</div>
|
||||
@@ -54,6 +60,8 @@
|
||||
<script>
|
||||
import ConsoleScreen from "./screen_console.vue";
|
||||
|
||||
import "./screens.css";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ConsoleScreen
|
||||
@@ -81,6 +89,12 @@ export default {
|
||||
stopped(index, stopErr) {
|
||||
this.$emit("stopped", index, stopErr);
|
||||
},
|
||||
warning(index, msg) {
|
||||
this.$emit("warning", index, msg);
|
||||
},
|
||||
info(index, msg) {
|
||||
this.$emit("info", index, msg);
|
||||
},
|
||||
updated(index) {
|
||||
this.$emit("updated", index);
|
||||
}
|
||||
|
||||
@@ -24,7 +24,9 @@
|
||||
:key="tabInfo.id"
|
||||
:class="{
|
||||
active: tab === idx,
|
||||
error: tabInfo.indicator.error.length > 0,
|
||||
error:
|
||||
tabInfo.indicator.message.length > 0 &&
|
||||
tabInfo.indicator.level === 'error',
|
||||
updated: tabInfo.indicator.updated && tab !== idx
|
||||
}"
|
||||
:style="
|
||||
|
||||
Reference in New Issue
Block a user