Move resume to external repo
This commit is contained in:
commit
9d414158e7
|
@ -0,0 +1,7 @@
|
||||||
|
node_modules
|
||||||
|
yarn.lock
|
||||||
|
package-lock.json
|
||||||
|
dist
|
||||||
|
|
||||||
|
*.log
|
||||||
|
*.tmp
|
|
@ -0,0 +1,37 @@
|
||||||
|
{
|
||||||
|
"name": "resume",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "src/resume.js",
|
||||||
|
"source": "src/index.html",
|
||||||
|
"author": "blek",
|
||||||
|
"license": "MIT",
|
||||||
|
"devDependencies": {
|
||||||
|
"assert": "^2.0.0",
|
||||||
|
"events": "^3.1.0",
|
||||||
|
"parcel": "^2.8.3",
|
||||||
|
"parcel-namer-without-hash": "^0.0.1",
|
||||||
|
"path-browserify": "^1.0.0",
|
||||||
|
"process": "^0.11.10",
|
||||||
|
"punycode": "^1.4.1",
|
||||||
|
"querystring-es3": "^0.2.1",
|
||||||
|
"stream-browserify": "^3.0.0",
|
||||||
|
"url": "^0.11.0",
|
||||||
|
"util": "^0.12.3"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@parcel/fs": "^2.8.3",
|
||||||
|
"copy-to-clipboard": "^3.3.3",
|
||||||
|
"file-saver": "^2.0.5",
|
||||||
|
"memfs": "^3.4.13",
|
||||||
|
"react": "^18.2.0",
|
||||||
|
"react-dom": "^18.2.0",
|
||||||
|
"unionfs": "^4.4.0",
|
||||||
|
"xterm": "^5.1.0",
|
||||||
|
"xterm-for-react": "^1.0.4",
|
||||||
|
"xterm-js-shell": "^1.1.3"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"start": "parcel",
|
||||||
|
"build": "parcel build --no-source-maps"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { XTerm } from 'xterm-for-react'
|
||||||
|
|
||||||
|
export class Console extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.terminal = React.createRef(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return <div style={{padding: '8px'}}>
|
||||||
|
<XTerm
|
||||||
|
ref={this.terminal}
|
||||||
|
options={{
|
||||||
|
theme: {
|
||||||
|
background: '#212121',
|
||||||
|
brightGreen: '#15a179'
|
||||||
|
},
|
||||||
|
convertEol: true
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
require('./emulator')(this.terminal.current);
|
||||||
|
this.terminal.current.terminal.focus();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
import { Terminal } from 'xterm';
|
||||||
|
const fs = require('../fs');
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param { string[] } argv
|
||||||
|
* @param { Terminal } terminal
|
||||||
|
*/
|
||||||
|
module.exports = (argv, terminal) => {
|
||||||
|
if (argv.indexOf('--help') != -1) {
|
||||||
|
terminal.writeln(`Usage: ${argv[0]} [files] [-n]`);
|
||||||
|
terminal.writeln(' -n --number show lines numbers');
|
||||||
|
terminal.writeln(' --help show this help');
|
||||||
|
terminal.writeln('Read files into stdout');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const numbers = (argv.indexOf('-n') != -1) || (argv.indexOf('--number') != -1);
|
||||||
|
|
||||||
|
let files = argv.filter(x => { return !x.startsWith('-') });
|
||||||
|
files.shift();
|
||||||
|
files.forEach(file => {
|
||||||
|
if (!fs.existsSync(file)) {
|
||||||
|
terminal.writeln(`${argv[0]}: ${file}: no such file or directory`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const lines = fs.readFileSync(file).toString().split('\n');
|
||||||
|
|
||||||
|
if (numbers) {
|
||||||
|
lines.forEach((line, i) => {
|
||||||
|
terminal.write('\033[35m' + i + ' |\033[0m ');
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
terminal.write(lines.join('\n'));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { Terminal } from 'xterm';
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {string[]} argv
|
||||||
|
* @param {Terminal} terminal
|
||||||
|
*/
|
||||||
|
module.exports = (argv, terminal) => {
|
||||||
|
if (argv.indexOf('--help') != -1) {
|
||||||
|
terminal.writeln(`Usage: ${argv[0]} [--help]`);
|
||||||
|
terminal.writeln('Lists all available commands.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const cmds = Object.keys(require('../commands'));
|
||||||
|
let i = 0;
|
||||||
|
cmds.forEach(x => {
|
||||||
|
if (x == argv[0]) return;
|
||||||
|
if (i == 4) {
|
||||||
|
terminal.writeln('');
|
||||||
|
i = 0;
|
||||||
|
} else i++;
|
||||||
|
terminal.write('\033[1;32m' + x + '\033[0m ');
|
||||||
|
});
|
||||||
|
terminal.writeln('');
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
import { Terminal } from 'xterm';
|
||||||
|
import { saveAs } from 'file-saver';
|
||||||
|
const fs = require('../fs');
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param { string[] } argv
|
||||||
|
* @param { Terminal } terminal
|
||||||
|
*/
|
||||||
|
module.exports = (argv, terminal) => {
|
||||||
|
if (argv.indexOf('--help') != -1 || argv.length == 1) {
|
||||||
|
terminal.write(
|
||||||
|
`Usage: ${argv[0]} [FILES] [-z]
|
||||||
|
Export file from filesystem to your device.
|
||||||
|
-z Compress in zip format (not supported)`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let files = [...argv];
|
||||||
|
files.shift();
|
||||||
|
|
||||||
|
if (argv.indexOf('-z') != -1) {
|
||||||
|
terminal.write(`${argv[0]}: cannot zip '${files.join(' ').replace('\'', "\\'")}': not supported\n`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
var isFileSaverSupported = !!new Blob;
|
||||||
|
} catch (e) {}
|
||||||
|
|
||||||
|
if (!isFileSaverSupported) {
|
||||||
|
terminal.write(`${argv[0]}: Your browser does not support this feature.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fs.existsSync(argv[1])) {
|
||||||
|
terminal.write(`${argv[0]}: cannot open ${argv[1]}: no such file or directory\n`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
saveAs(new Blob([fs.readFileSync(argv[1])]), argv[1]);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
import { Terminal } from 'xterm';
|
||||||
|
import { saveAs } from 'file-saver';
|
||||||
|
const fs = require('../fs');
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param { string[] } argv
|
||||||
|
* @param { Terminal } terminal
|
||||||
|
*/
|
||||||
|
module.exports = (argv, terminal) => {
|
||||||
|
|
||||||
|
if (argv.indexOf('--help') != -1) {
|
||||||
|
terminal.write(
|
||||||
|
`Usage: ${argv[0]} [DESTANATION]\n
|
||||||
|
Import files from your system to this filesystem.
|
||||||
|
`
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let el = document.getElementById('upload_file_btn');
|
||||||
|
if (el == null) {
|
||||||
|
el = document.createElement('input');
|
||||||
|
el.style.display = 'none';
|
||||||
|
el.type = 'file';
|
||||||
|
el.id = 'upload_file_btn';
|
||||||
|
el.setAttribute('multiple', 'multiple');
|
||||||
|
document.body.appendChild(el);
|
||||||
|
}
|
||||||
|
|
||||||
|
const dir = argv[1] || '.';
|
||||||
|
|
||||||
|
el.click();
|
||||||
|
|
||||||
|
let files = el.files;
|
||||||
|
global.f = files
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
let cmds = {
|
||||||
|
'cat': require('./cat'),
|
||||||
|
'cmds': require('./cmds'),
|
||||||
|
'cmdls': require('./cmds'),
|
||||||
|
'help': require('./cmds'),
|
||||||
|
'ls': require('./ls'),
|
||||||
|
'skills': require('./skills'),
|
||||||
|
'mkdir': require('./mkdir'),
|
||||||
|
'wget': require('./wget'),
|
||||||
|
'export_file': require('./export_file'),
|
||||||
|
'import_file': require('./import_file'),
|
||||||
|
'zsh': require('./zsh'),
|
||||||
|
|
||||||
|
// alias l='ls -l'
|
||||||
|
'l': (a,t) => {require('./ls')([...a, '-l'], t)},
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = cmds;
|
|
@ -0,0 +1,67 @@
|
||||||
|
const { Terminal } = require('xterm');
|
||||||
|
const fs = require('../fs');
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {string[]} argv
|
||||||
|
* @param {Terminal} terminal
|
||||||
|
*/
|
||||||
|
module.exports = (argv, terminal) => {
|
||||||
|
if (argv.indexOf('--help') != -1) {
|
||||||
|
terminal.writeln(`Usage: ${argv[0]} [dirs] [-a|--all] [-l]`);
|
||||||
|
terminal.writeln('Lists files in directories');
|
||||||
|
terminal.writeln(' -a --all List all files (including those who start with .)');
|
||||||
|
terminal.writeln(' -l Use long listing format');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const has_arg = (arg) => {return argv.indexOf(arg) != -1};
|
||||||
|
|
||||||
|
let directories = [...argv];
|
||||||
|
|
||||||
|
const all = (has_arg('-a') || has_arg('--all'));
|
||||||
|
const long_format = has_arg('-l');
|
||||||
|
|
||||||
|
directories.shift();
|
||||||
|
|
||||||
|
// remove .* files if -a not specified
|
||||||
|
if (!all)
|
||||||
|
directories = directories.filter(x => !x.startsWith('.'));
|
||||||
|
|
||||||
|
// remove arguments
|
||||||
|
directories = directories.filter(x => !x.startsWith('-'));
|
||||||
|
|
||||||
|
if (directories.length == 0) directories = ['.'];
|
||||||
|
|
||||||
|
// remove dublicates
|
||||||
|
directories = [...new Set(directories)];
|
||||||
|
|
||||||
|
directories.forEach((dir, i) => {
|
||||||
|
|
||||||
|
if (!fs.lstatSync(dir).isDirectory()) {
|
||||||
|
terminal.write(dir);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (directories.length != 1) {
|
||||||
|
terminal.writeln(dir + ':');
|
||||||
|
terminal.writeln('');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fs.existsSync(dir)) {
|
||||||
|
terminal.writeln(`${argv[0]}: cannot access '${dir}': No such file or directory`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let files = fs.readdirSync(dir);
|
||||||
|
files.forEach((file, i) => {
|
||||||
|
|
||||||
|
if (!long_format)
|
||||||
|
terminal.write(file + '\033[0m ');
|
||||||
|
else
|
||||||
|
terminal.writeln('drwx-xr-x 1 nobody nobody 4.0K Jan 1 13 01:00 ' + file);
|
||||||
|
if ((i+1) % 5 == 0)
|
||||||
|
terminal.writeln('');
|
||||||
|
});
|
||||||
|
})
|
||||||
|
terminal.writeln('');
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
import { Terminal } from 'xterm';
|
||||||
|
const fs = require('../fs');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string[]} argv
|
||||||
|
* @param {Terminal} terminal
|
||||||
|
*/
|
||||||
|
module.exports = (argv, terminal) => {
|
||||||
|
if (argv.indexOf('--help') != -1) {
|
||||||
|
terminal.write(`
|
||||||
|
Usage: ${argv[0]} [DIRECTORY] [-p]
|
||||||
|
Create a directory
|
||||||
|
-p Create parent directories
|
||||||
|
`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const parents = argv.indexOf('-p') != -1;
|
||||||
|
const dir = argv[1];
|
||||||
|
|
||||||
|
try {
|
||||||
|
fs.mkdirSync(dir, {recursive: parents});
|
||||||
|
} catch (err) {
|
||||||
|
terminal.write(`${argv[0]}: can't create ${dir}: ${err}`);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
const fs = require('../fs');
|
||||||
|
|
||||||
|
module.exports = (argv, terminal) => {
|
||||||
|
|
||||||
|
if (argv.indexOf('--help') != -1) {
|
||||||
|
terminal.writeln(`Usage: ${argv[0]}\nShows my skills info`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argv[1] != undefined) {
|
||||||
|
const file = 'skills/' + argv[1];
|
||||||
|
if (!fs.existsSync(file))
|
||||||
|
return;
|
||||||
|
terminal.write(fs.readFileSync(file));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
terminal.write(`
|
||||||
|
My skills
|
||||||
|
|
||||||
|
\x1b[1;32m[#####] 100% Web dev (fullstack)\x1b[0m
|
||||||
|
I like doing backend mostly, but sometimes i do
|
||||||
|
frontend projects like this one.
|
||||||
|
Learn more: \x1b[4;32mskills web\x1b[0m
|
||||||
|
|
||||||
|
\x1b[1;33m[## ] 40% Native C/C++/Rust\x1b[0m
|
||||||
|
Not really my zone of work but its really fun to
|
||||||
|
make something with these in spare time.
|
||||||
|
Learn more: \x1b[4;32mskills nt\x1b[0m
|
||||||
|
|
||||||
|
\x1b[1;38:5:244m[ ] 0% Being cis\x1b[0m
|
||||||
|
Never liked it
|
||||||
|
`);
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
import { Terminal } from 'xterm';
|
||||||
|
const fs = require('../fs');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string[]} argv
|
||||||
|
* @param {Terminal} terminal
|
||||||
|
*/
|
||||||
|
module.exports = async (argv, terminal) => {
|
||||||
|
if (argv.indexOf('--help') != -1) {
|
||||||
|
terminal.write(`
|
||||||
|
Usage: ${argv[0]} [URL] [-O out.file] [-V] [-Q] [-s]
|
||||||
|
--help Show this help
|
||||||
|
-O [FILE] Specify output file
|
||||||
|
-V Verbose mode
|
||||||
|
-Q Quiet mode (default)
|
||||||
|
`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = argv[1];
|
||||||
|
|
||||||
|
let filepath = url.split('/')[url.split('/').length - 1];
|
||||||
|
|
||||||
|
if (argv.indexOf('-O') != -1) {
|
||||||
|
if (argv.indexOf('-O') + 1 == argv.length) {
|
||||||
|
terminal.writeln(`${argv[0]}: missing output file`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
filepath = argv[argv.indexOf('-O') + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
function progress(p) {
|
||||||
|
let total = p.total;
|
||||||
|
|
||||||
|
if (total == 0)
|
||||||
|
total = '?'
|
||||||
|
// terminal.write(`\rDownloading... ${p.loaded}/${total}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function write(file) {
|
||||||
|
if (filepath == '-') {
|
||||||
|
terminal.write(file);
|
||||||
|
} else {
|
||||||
|
fs.writeFileSync(filepath, new Buffer(file));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let file;
|
||||||
|
|
||||||
|
let req = new XMLHttpRequest();
|
||||||
|
req.open('GET', 'http://cors.blek.codes/' + url, true);
|
||||||
|
req.responseType = 'arraybuffer';
|
||||||
|
req.onprogress = progress;
|
||||||
|
req.onload = (e) => {
|
||||||
|
if (e.type == 'load') {
|
||||||
|
write(req.response);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
req.send();
|
||||||
|
|
||||||
|
const delay = t => new Promise(resolve => setTimeout(resolve, t));
|
||||||
|
while(req.readyState == 1) await delay(250);
|
||||||
|
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
const { Terminal } = require("xterm");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Terminal} terminal
|
||||||
|
*/
|
||||||
|
module.exports = (argv, terminal) => {
|
||||||
|
window.location.href = 'https://youtu.be/dQw4w9WgXcQ?t=3'
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
module.exports = {
|
||||||
|
'/skills/web': `
|
||||||
|
\x1b[1mMy web experience\x1b[0m
|
||||||
|
I don't really know anything about web development,
|
||||||
|
but I have some projects which are presented below:
|
||||||
|
|
||||||
|
blek! Site: Second rewrite of my website. https://github.com/b1ek/blekSite
|
||||||
|
blek! ID: An auth server. https://github.com/b1ek/blekID
|
||||||
|
blek! Bin: A pastebin alternative. https://git.blek.codes/blek/bin
|
||||||
|
homepage.js: Third rewrite of my website. https://git.blek.codes/blek/homepage.js
|
||||||
|
`,
|
||||||
|
'/skills/nt': `
|
||||||
|
Me native dev experience
|
||||||
|
It isn't much but i do have a couple of projects
|
||||||
|
(most of my native work is toy projects)
|
||||||
|
|
||||||
|
CuteSchedule A school project that is
|
||||||
|
supposed to be a interactive https://github.com/b1ek/CuteSchedule
|
||||||
|
schedule menu hanging on
|
||||||
|
a TV
|
||||||
|
f2bin Convert files into C code https://github.com/b1ek/f2bin`
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
const { fs, vol } = require('memfs');
|
||||||
|
fs.writeFileSync('README.md', 'uwu');
|
||||||
|
const { ufs } = require('unionfs');
|
||||||
|
|
||||||
|
ufs.use(fs).use(vol.fromJSON(require('./files')));
|
||||||
|
ufs.constants = fs.constants;
|
||||||
|
|
||||||
|
module.exports = ufs;
|
|
@ -0,0 +1,11 @@
|
||||||
|
module.exports = (dom) => {
|
||||||
|
const terminal = dom.terminal;
|
||||||
|
|
||||||
|
terminal.writeln('Welcome to my online resume!')
|
||||||
|
terminal.writeln('Type \033[1;32mhelp\033[0m for list of commands')
|
||||||
|
terminal.writeln('Use \033[1;33mAlt+C/V\033[0m to copy or paste');
|
||||||
|
terminal.writeln('');
|
||||||
|
|
||||||
|
require('./zsh')(terminal, dom);
|
||||||
|
require('./pastebuffer')(terminal, dom);
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
import { Terminal } from "xterm"
|
||||||
|
import copy from 'copy-to-clipboard';
|
||||||
|
|
||||||
|
/** @type { Terminal } */
|
||||||
|
let terminal;
|
||||||
|
const zsh = require('./zsh');
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {{ key: string, domEvent: KeyboardEvent }} e
|
||||||
|
*/
|
||||||
|
async function keyHandler(e) {
|
||||||
|
const dom = e.domEvent;
|
||||||
|
|
||||||
|
if (!dom.altKey)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (dom.key.length != 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (dom.key.toLowerCase()) {
|
||||||
|
case 'c':
|
||||||
|
if (!terminal.hasSelection()) break;
|
||||||
|
|
||||||
|
copy(terminal.getSelection())
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
zsh.pr_char(prompt("Paste your text:"), {key: 'a'})
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = (t, d) => {
|
||||||
|
terminal = t;
|
||||||
|
terminal.onKey(keyHandler);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,230 @@
|
||||||
|
|
||||||
|
import { Terminal } from 'xterm';
|
||||||
|
import { XTerm } from 'xterm-for-react';
|
||||||
|
|
||||||
|
const fs = require('./fs');
|
||||||
|
global.fs = fs;
|
||||||
|
const cmds = require('./commands');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type { Terminal }
|
||||||
|
*/
|
||||||
|
let terminal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type { XTerm }
|
||||||
|
*/
|
||||||
|
let dom;
|
||||||
|
|
||||||
|
const prompt = '\033[1;32muser@blek.codes \033[36m~ $ \033[0m';
|
||||||
|
let cmd = '';
|
||||||
|
let lastcmd = window.sessionStorage.getItem('last_cmd') || '';
|
||||||
|
|
||||||
|
function text_prompt() {
|
||||||
|
return prompt.replace(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param { string } char
|
||||||
|
* @param { KeyboardEvent } dom
|
||||||
|
*/
|
||||||
|
function pr_char(char, dom) {
|
||||||
|
if (dom.key.length != 1) return;
|
||||||
|
|
||||||
|
cmd += char;
|
||||||
|
terminal.write(char);
|
||||||
|
}
|
||||||
|
|
||||||
|
function exec_file(f) {
|
||||||
|
|
||||||
|
const exists = fs.existsSync(f);
|
||||||
|
if (!exists) {
|
||||||
|
terminal.write('zsh: no such file or directory: ' + f);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const executable = fs.accessSync(f, fs.constants.X_OK);
|
||||||
|
if (!executable) {
|
||||||
|
terminal.writeln('zsh: permission denied: ' + f);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
terminal.writeln('This is an online resume. It is not big enough to have a script runtime.\n');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function exec_cmd() {
|
||||||
|
let c = cmd;
|
||||||
|
const command = c.split(' ')[0];
|
||||||
|
reset_cmd(c);
|
||||||
|
lastcmd = c;
|
||||||
|
window.sessionStorage.setItem('last_cmd', c);
|
||||||
|
|
||||||
|
if (command == '') {
|
||||||
|
print_prompt();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if path
|
||||||
|
if (command.match(/^((\.|\.\.)\/|\/).+$/gm)) {
|
||||||
|
exec_file(command);
|
||||||
|
terminal.writeln('');
|
||||||
|
print_prompt();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmds[command] != undefined) {
|
||||||
|
const startY = terminal.buffer.normal.cursorY
|
||||||
|
|
||||||
|
await cmds[command](c.split(' '), terminal);
|
||||||
|
|
||||||
|
await (new Promise(resolve => setTimeout(resolve, 10)));
|
||||||
|
|
||||||
|
if (terminal.buffer.active.cursorX != 0 && startY != terminal.buffer.active.cursorY) {
|
||||||
|
terminal.write('\033[30;47m%\033[0m\n');
|
||||||
|
}
|
||||||
|
print_prompt();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
terminal.writeln('zsh: command not found: ' + command);
|
||||||
|
print_prompt();
|
||||||
|
}
|
||||||
|
|
||||||
|
function print_prompt() {
|
||||||
|
terminal.write(prompt);
|
||||||
|
}
|
||||||
|
|
||||||
|
function reprint_prompt() {
|
||||||
|
terminal.write('\033[2K\r');
|
||||||
|
print_prompt();
|
||||||
|
}
|
||||||
|
|
||||||
|
function reset_cmd() {
|
||||||
|
cmd = '';
|
||||||
|
terminal.writeln('');
|
||||||
|
}
|
||||||
|
|
||||||
|
function cbackspace() {
|
||||||
|
let exploded = cmd.substring(0, cmd.length - 2).split(' ');
|
||||||
|
|
||||||
|
if (exploded.length == 1) {
|
||||||
|
reprint_prompt();
|
||||||
|
cmd = '';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
exploded.pop();
|
||||||
|
|
||||||
|
cmd = exploded.join(' ') + ' ';
|
||||||
|
reprint_prompt();
|
||||||
|
terminal.write(cmd);
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function backspace(isCtrl) {
|
||||||
|
if (terminal.buffer.active.cursorX <= text_prompt().length) return;
|
||||||
|
|
||||||
|
if (isCtrl) {
|
||||||
|
return cbackspace();
|
||||||
|
}
|
||||||
|
|
||||||
|
terminal.write('\b \b');
|
||||||
|
cmd = cmd.substring(0, cmd.length - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @param { KeyboardEvent } dom */
|
||||||
|
async function control_char(id, dom) {
|
||||||
|
|
||||||
|
switch (id) {
|
||||||
|
|
||||||
|
// backspace
|
||||||
|
case 8:
|
||||||
|
backspace(dom.ctrlKey);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// enter
|
||||||
|
case 13:
|
||||||
|
exec_cmd();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 38:
|
||||||
|
if (lastcmd == '') break;
|
||||||
|
cmd = lastcmd;
|
||||||
|
reprint_prompt();
|
||||||
|
terminal.write(lastcmd);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Ctrl+c
|
||||||
|
case 67:
|
||||||
|
if (dom.ctrlKey) {
|
||||||
|
terminal.write('^C');
|
||||||
|
reset_cmd();
|
||||||
|
print_prompt();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 86:
|
||||||
|
if (dom.altKey) break;
|
||||||
|
|
||||||
|
case 82:
|
||||||
|
// Why it checks if letter is 'r':
|
||||||
|
// For some reason, ctrl+(v|r|d) executed this code.
|
||||||
|
// This is a simple fix
|
||||||
|
// (same works for any other code like this in this function)
|
||||||
|
if (dom.ctrlKey && dom.key.toLowerCase() == 'r') {
|
||||||
|
if (Math.random() < 0.1) terminal.write('uwu');
|
||||||
|
window.location.reload();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 68:
|
||||||
|
if (dom.ctrlKey && dom.key.toLowerCase() == 'd') {
|
||||||
|
terminal.writeln('');
|
||||||
|
pr_char = () => {};
|
||||||
|
exec_cmd = pr_char;
|
||||||
|
control_char = () => {};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
const wr = (t) => {
|
||||||
|
terminal.write(t);
|
||||||
|
cmd += t;
|
||||||
|
}
|
||||||
|
if (dom.ctrlKey && (dom.key.length == 1)) {
|
||||||
|
wr('^' + dom.key.toUpperCase());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
wr('<');
|
||||||
|
if (dom.ctrlKey) wr('C');
|
||||||
|
if (dom.altKey) wr('A');
|
||||||
|
if (dom.shiftKey) wr('S');
|
||||||
|
wr(`${id}>`)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function key(e) {
|
||||||
|
/** @type {KeyboardEvent} */
|
||||||
|
const dom = e.domEvent;
|
||||||
|
if (dom.key.length == 1 && !(dom.ctrlKey || dom.altKey)) {
|
||||||
|
pr_char(e.domEvent.key, dom);
|
||||||
|
} else {
|
||||||
|
control_char(e.domEvent.keyCode, dom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function register(t, d) {
|
||||||
|
terminal = t;
|
||||||
|
dom = d;
|
||||||
|
|
||||||
|
terminal.onKey(key);
|
||||||
|
terminal.write(prompt);
|
||||||
|
}
|
||||||
|
|
||||||
|
register.pr_char = pr_char;
|
||||||
|
|
||||||
|
module.exports = register;
|
|
@ -0,0 +1,13 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>resume.js</title>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<link rel="stylesheet" href="rootstyle.css" />
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="resume_js_app"></div>
|
||||||
|
<script src="resume.js" type="module"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,43 @@
|
||||||
|
div#resume_js_app {
|
||||||
|
background: #212121;
|
||||||
|
width:1000px;
|
||||||
|
height:800px;
|
||||||
|
border: 1px solid #e1e1e1;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-family: monospace;
|
||||||
|
box-shadow: 0 2px 1px #303030A0;
|
||||||
|
color: #e1e1e1 !important;
|
||||||
|
padding: 8px 2px;
|
||||||
|
transition: 150ms ease;
|
||||||
|
}
|
||||||
|
div#resume_js_app:hover {
|
||||||
|
box-shadow: 0 2px 3px #303030;
|
||||||
|
}
|
||||||
|
div#resume_js_app p.js_loading_indicator {
|
||||||
|
padding: 0; margin: 0;
|
||||||
|
position: relative;
|
||||||
|
top: 50%; left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
width: fit-content;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
div#resume_js_app * {
|
||||||
|
color: #e1e1e1;
|
||||||
|
font-family: 'Source Code Pro', monospace !important;
|
||||||
|
}
|
||||||
|
div#resume_js_app a, div#resume_js_app a:visited {
|
||||||
|
color: rgb(36, 85, 126) !important;
|
||||||
|
text-decoration: none;
|
||||||
|
font-weight: 500;
|
||||||
|
transition: 150ms ease;
|
||||||
|
text-shadow: 0 0 0px #24557e30;
|
||||||
|
}
|
||||||
|
div#resume_js_app a:hover {
|
||||||
|
text-shadow: 0 0 4px #24557e30;
|
||||||
|
}
|
||||||
|
div#resume_js_app table * {
|
||||||
|
border:0;
|
||||||
|
text-align: left;
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>resume.js</title>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<link rel="stylesheet" href="/resume.css">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="resume_js_app"></div>
|
||||||
|
<script src="/resume.js" type="module"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,5 @@
|
||||||
|
import { Console } from './Console';
|
||||||
|
import ReactDOM from 'react-dom/client';
|
||||||
|
|
||||||
|
const root = ReactDOM.createRoot(document.getElementById('resume_js_app'));
|
||||||
|
root.render(<Console />)
|
|
@ -0,0 +1 @@
|
||||||
|
../../../public/static/ui/resume.css
|
Loading…
Reference in New Issue