first commit
This commit is contained in:
56
xterminal/docs/public/demo.html
Normal file
56
xterminal/docs/public/demo.html
Normal file
@@ -0,0 +1,56 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Live Demo | XTerminal</title>
|
||||
<link rel="stylesheet" href="https://unpkg.com/xterminal/dist/xterminal.css">
|
||||
<style>
|
||||
*, *::after, *::before {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
html, body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
#app {
|
||||
height: 100vh;
|
||||
}
|
||||
:root {
|
||||
--xt-fg: lime;
|
||||
--xt-bg: black;
|
||||
}
|
||||
.xt {
|
||||
padding: 10px;
|
||||
line-height: 1.215;
|
||||
}
|
||||
.error {
|
||||
color: rgb(248, 88, 88);
|
||||
}
|
||||
.spinner:after {
|
||||
animation: changeContent 0.8s linear infinite;
|
||||
content: "⠋";
|
||||
}
|
||||
|
||||
@keyframes changeContent {
|
||||
10% { content: "⠙"; }
|
||||
20% { content: "⠹"; }
|
||||
30% { content: "⠸"; }
|
||||
40% { content: "⠼"; }
|
||||
50% { content: "⠴"; }
|
||||
60% { content: "⠦"; }
|
||||
70% { content: "⠧"; }
|
||||
80% { content: "⠇"; }
|
||||
90% { content: "⠏"; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script src="https://unpkg.com/xterminal/dist/xterminal.umd.js"></script>
|
||||
<script src="./demo.js"></script>
|
||||
<script>
|
||||
window.onload = () => createTerminal('#app');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
149
xterminal/docs/public/demo.js
Normal file
149
xterminal/docs/public/demo.js
Normal file
@@ -0,0 +1,149 @@
|
||||
/**
|
||||
* Create a demo shell object
|
||||
*/
|
||||
|
||||
// #region shell
|
||||
function createShell() {
|
||||
|
||||
// Help
|
||||
const manual = `XTerminal : version ${XTerminal.version}
|
||||
|
||||
Type 'help' to see this list
|
||||
|
||||
Commands:
|
||||
|
||||
gh (username) search for github users
|
||||
js [expr] execute a JS expression
|
||||
clear clear the terminal screen
|
||||
help display this list
|
||||
`;
|
||||
|
||||
// Get public github user information
|
||||
async function fetchGitHubUser(username) {
|
||||
return fetch('https://api.github.com/users/' + username)
|
||||
.then(res => res.json())
|
||||
.then(res => {
|
||||
return(
|
||||
'<table border="0">' +
|
||||
'<tr>' +
|
||||
`<td rowspan="3" width="100"><img width="75" src="${res.avatar_url}" alt="${res.name}" /></td>` +
|
||||
`<td>Name</td>` +
|
||||
`<td>${res.name}</td>` +
|
||||
'</tr>' +
|
||||
'<tr>' +
|
||||
`<td>Bio</td>` +
|
||||
`<td>${res.bio}</td>` +
|
||||
'</tr>' +
|
||||
'<tr>' +
|
||||
`<td>Repos</td>` +
|
||||
`<td>${res.public_repos}</td>` +
|
||||
'</tr>' +
|
||||
'</table>'
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// evaluate user input from the terminal
|
||||
// -> can be shared among several terminal objects
|
||||
function execute(term, command = '') {
|
||||
let args = command.split(' ');
|
||||
let cmd = args.shift();
|
||||
// GitHub User Search
|
||||
if (cmd == 'gh') {
|
||||
return new Promise(async (res, rej) => {
|
||||
let output, error;
|
||||
term.write('<span class="spinner"></span> Searching...');
|
||||
await fetchGitHubUser(args.join(''))
|
||||
.then(val => output = val)
|
||||
.catch(err => error = ':( Not found!')
|
||||
.finally(() => term.clearLast());
|
||||
if (error) rej(error);
|
||||
else res(output);
|
||||
});
|
||||
}
|
||||
// JavaScript Evaluation
|
||||
else if (cmd == 'js') {
|
||||
return new Promise((res, rej) => {
|
||||
try {
|
||||
let output = eval(args.join(' ')) + '\n';
|
||||
res(output);
|
||||
} catch (error) {
|
||||
rej(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
// Help menu
|
||||
else if (cmd == 'help') {
|
||||
return Promise.resolve(manual);
|
||||
}
|
||||
// Clear the terminal
|
||||
else if (cmd == 'clear') {
|
||||
term.clear();
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
// Oopps!
|
||||
else {
|
||||
return Promise.reject(`sh: '${cmd}' command not found`);
|
||||
}
|
||||
}
|
||||
|
||||
return { execute };
|
||||
|
||||
}
|
||||
// #endregion shell
|
||||
|
||||
/**
|
||||
* Create a fresh terminal object
|
||||
*/
|
||||
|
||||
// #region terminal
|
||||
function createTerminal(target) {
|
||||
|
||||
const term = new XTerminal({ target });
|
||||
|
||||
const state = {
|
||||
username: "user",
|
||||
hostname: "web"
|
||||
};
|
||||
|
||||
// input evaluator
|
||||
const shell = createShell();
|
||||
|
||||
// print prompt and get ready for user input
|
||||
function promptUser() {
|
||||
term.write(`┌[${state.username}@${state.hostname}]\n`);
|
||||
term.write("└$ ");
|
||||
term.resume();
|
||||
term.focus();
|
||||
}
|
||||
|
||||
// user input handler
|
||||
term.on("data", async input => {
|
||||
|
||||
// deactivate until the execution is done
|
||||
term.pause();
|
||||
|
||||
// execute command
|
||||
await shell.execute(term, input)
|
||||
.then(res => res && term.writeln(res))
|
||||
.catch(err => {
|
||||
if (err) {
|
||||
// sanitize error to prevent xss attacks
|
||||
// error may contain user input or HTML strings (like script tags)
|
||||
term.writeln(`<span class="error">${XTerminal.escapeHTML(err)}</span>\n`)
|
||||
}
|
||||
})
|
||||
.finally(promptUser);
|
||||
});
|
||||
|
||||
// greeting message
|
||||
term.writeln("Welcome to XTerminal (v" + XTerminal.version + ")");
|
||||
term.writeln("Type `help` for available commands\n");
|
||||
|
||||
// kickstart
|
||||
promptUser();
|
||||
|
||||
// remember to free resources
|
||||
window.addEventListener('unload', () => term.dispose());
|
||||
}
|
||||
// #endregion terminal
|
||||
BIN
xterminal/docs/public/logo.ico
Normal file
BIN
xterminal/docs/public/logo.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 100 KiB |
9
xterminal/docs/public/logo.svg
Normal file
9
xterminal/docs/public/logo.svg
Normal file
@@ -0,0 +1,9 @@
|
||||
<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">
|
||||
<g>
|
||||
<title>XTerminal Logo</title>
|
||||
<path stroke="#000" d="m-4,-2.5l103.99998,0l0,108l-103.99998,0l0,-108z" stroke-width="0" fill="#444444"/>
|
||||
<rect stroke="#000" height="33" width="16" y="29" x="42" stroke-width="0" fill="#ffffff"/>
|
||||
<rect transform="rotate(-45 23.25 40.25)" stroke="#000" height="18.56497" width="6.17157" y="30.96751" x="20.16421" stroke-width="0" fill="#ffffff"/>
|
||||
<rect transform="rotate(45 22.6036 50.25)" stroke="#000" height="18.75736" width="6" y="40.87132" x="19.60356" stroke-width="0" fill="#ffffff"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 616 B |
Reference in New Issue
Block a user