diff options
-rwxr-xr-x | _notes_cli.js | 167 | ||||
-rw-r--r-- | notes.js | 173 |
2 files changed, 340 insertions, 0 deletions
diff --git a/_notes_cli.js b/_notes_cli.js new file mode 100755 index 0000000..904f493 --- /dev/null +++ b/_notes_cli.js @@ -0,0 +1,167 @@ +const fs = require('fs') +const { homedir } = require('os') + +let conf + +const https = require('https') +const readline = require("readline") +// const spawn = require('child_process').spawn + +const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout +}) + +const cl = (m, c) => console.log(c ? `\x1b[${c}m${m}\x1b[0m` : m) +const cls = () => console.clear() + +const configPath = `${homedir}/.local/share/notes_cli` +console.log(configPath) + +const setConf = (c, callback) => { + fs.writeFile(configPath, JSON.stringify(c), function(err) { + if(err) { + cl(err, 32) + cl('Error writting configuration file', 32) + return null + } + + conf = c + return callback() + }) +} + +const getConf = () => { + fs.readFile(configPath, function(err, f){ + if (err) { + cl('Configuration file not found', 33) + return login() + } + + try { + const r = JSON.parse(f.toString()) + + console.log(r) + + if (!r.session || !r.userId || !r.email || !r.list) { + cl('Error parsing configuration', 31) + process.exit(1) + } + + conf = r + return console.log('here handle config') + + // + + } catch (e) { + cl('Error reading configuration', 31) + process.exit(1) + } + }) +} + +const post = (path, data, callback) => { + const dataString = JSON.stringify(data) + const options = { + hostname: 'apps.pruss.it', + port: 443, + path, + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Content-Length': dataString.length + }, + timeout: 1000 + }; + + const req = https.request(options, (res) => { + let data = ''; + + res.on('data', (chunk) => { + data += chunk; + }); + + res.on('end', () => { + return callback(JSON.parse(data), res.headers, res.statusCode); + }); + + }).on("error", () => { + callback(null) + }); + + req.write(dataString); + req.end(); +} + +const login = () => { + cl('\nLogin to My Apps\n', 32) + cl('+-------------------------------------------------------+\n'+ + '|Account can be created through apps.pruss.it website.|\n'+ + '|To quit type "q" and press enter. |\n'+ + '+-------------------------------------------------------+\n', 32) + rl.resume() + rl.question('Email: ', e => { + if (e === 'q') { + cl('\nExiting My Apps', 31) + rl.close() + process.exit(1) + } else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(e)) { + cls() + cl('\nNot a valid email address, try again.', 31) + rl.pause() + return login() + } + + rl.stdoutMuted = true + + rl.question('Password: ', p => { + if (p === 'q') { + cl('\nExiting My Apps', 31) + rl.close() + process.exit(1) + } + + rl.pause() + + post( + '/api/login', + {"email": e, "password": p}, + (o, h, s) => { + if (!o || s !== 201) { + cl('Could not log in, try again', 31) + return login() + } + + const {_id, email, isVerified, noteList} = o + const session = h['set-cookie'] + + if (!_id || !email || !noteList) { + cl('Could not log in', 31) + process.exit(1) + } else if (!isVerified) { + cl('User not verified.\nPlease first verify the user using apps.pruss.it', 32) + return 1 + } + + const c = {userId: _id, email, list: noteList, session} + + setConf(c, () => { + cl('Successfully saved configuration', 32) + cl('saved config: ', conf) + }) + }) + }) + + rl._writeToOutput = function _writeToOutput(stringToWrite) { + if (rl.stdoutMuted) + rl.output.write("*") + else + rl.output.write(stringToWrite) + }; + + rl.history = rl.history.slice(1) + }) +} + +cls() +getConf() diff --git a/notes.js b/notes.js new file mode 100644 index 0000000..5aa7c2f --- /dev/null +++ b/notes.js @@ -0,0 +1,173 @@ +const rl = require('readline'); + +const list_mock = [ + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + '10', + '11', + '12', + '13', + '14', + '15', + '16', + '17', + '18', + '19', + '20', + '21', + '22', + '23', + '24', + '25', + '26', + '27', + '28', + '29', + '30', + '31', + '32', + '33', + '34', + '35', + '36', + '37', + '38', + '39', + '40', + '41', + '42', + '43', + '44', + '45', + '46', + '47', + '48', + '49', + '50' +] + +let active = 0; scroll = 0; draw = { t: 'p', v: ['Loading Notes App...'] }, appTitle = '', menu = '' +const pr = t => process.stdout.write(t) +const cls = () => console.clear() +const cursor = { + hide: () => pr('\u001B[?25l'), + show: () => pr('\u001B[?25h') +} + +// =========== DRAW APP ============= + +const drawApp = () => { + const lines = process.stdout.rows + const columns = process.stdout.columns + // process.stdout.write('\x1Bc') + cls() + for (var i = 0; i < lines - 1; i++) { + const dist = t => [Math.floor((columns - t) / 2), Math.ceil((columns - t) / 2) - 2] + switch(i){ + case 0: + pr('╔'+'═'.repeat(columns - 2)+'╗') + break + case 1: + pr('║'+' '.repeat(dist(appTitle.length)[0])+appTitle+' '.repeat(dist(appTitle.length)[1])+'║') + break + case 2: + pr('╠'+'═'.repeat(columns - 2) +'╣') + break + case lines - 3: + pr('╟'+'─'.repeat(columns - 2) +'╢') + break + case lines - 2: + pr('║'+' '+menu.substring(0,columns-4)+' '.repeat(columns-menu.length-3)+'║') + break + default: + const max = Math.max(...(draw.v.map(el => el.length))) + if (draw.t === 'p') { + if (i === (Math.floor((lines - draw.v.length) / 2) - 2)){ + pr('║'+' '.repeat(dist(max+4)[0])+'┌'+'─'.repeat(max+2)+'┐'+' '.repeat(dist(max+4)[1])+'║') + } else if (i === (Math.floor((lines + draw.v.length) / 2) + 1)) { + pr('║'+' '.repeat(dist(max+4)[0])+'└'+'─'.repeat(max+2)+'┘'+' '.repeat(dist(max+4)[1])+'║') + } else if (i === (Math.floor((lines - draw.v.length) / 2) - 1) || i === (Math.floor((lines + draw.v.length) / 2))) { + pr('║'+' '.repeat(dist(max+4)[0])+'│'+' '.repeat(max+2)+'│'+' '.repeat(dist(max+4)[1])+'║') + } else if (i < (Math.floor((lines - draw.v.length) / 2) - 1) || (i > (Math.floor((lines + draw.v.length) / 2)))) { + pr('║'+' '.repeat(columns - 2)+'║') + } else { + const n = i - (Math.floor((lines - draw.v.length) / 2)) + const t = draw.v[n] + const s = [Math.floor((max+2-t.length) / 2), Math.ceil((max+2-t.length) / 2)] + pr('║'+' '.repeat(dist(max+4)[0])+'│'+' '.repeat(s[0])+t+' '.repeat(s[1])+'│'+' '.repeat(dist(max+4)[1])+'║') + } + } else if (draw.t === 'l') { + const l = draw.v[i-3+scroll] && draw.v[i-3+scroll].substring(0,columns-4) + + pr(l + ? ('║'+(active===i-3+scroll?'\x1b[7m ':' ')+l+' '.repeat(columns-l.length-3)+'\x1b[0m║') + : ('║'+' '.repeat(columns - 2)+'║') + ) + } + } + } + + pr('╚'+'═'.repeat(columns - 2)+'╝') +} + +// ============ GET KEY ================= + +const getKey = () => { + rl.emitKeypressEvents(process.stdin); + process.stdin.setRawMode(true); + process.stdin.on('keypress', (_, key) => { + const lines = process.stdout.rows + switch(key.name) { + case 'up': + case 'k': + active > 0 && active-- + active < scroll && scroll-- + drawApp() + break + case 'down': + case 'j': + if (draw.t === 'l') { + active < draw.v.length - 1 && active++ + active - scroll > lines - 7 && scroll++ + drawApp() + } + break + case 'return': + case 'o': + // draw = { t: 'p', v: ['popup test'] } + // draw = { t: 'p', v: ['popup test', 'aaaaaaa'] } + draw = { t: 'p', v: ['popup test', '', `This will display note nr ${active + 1}.`] } + drawApp() + // process.stdout.write(draw.v[active]); + break + case 'q': + cursor.show() + console.clear() + pr('Bye!\n\n') + process.exit() + default: + } + }) +} + +// ============ EXECUTION ================ + +cls() +cursor.hide() +process.stdout.on('resize', drawApp); + +appTitle = "Notes App" +menu = '[Q]uit [↓/j] Down [↑/k] Up [Enter/o] Open' +draw = { t: 'l', v: list_mock } + +drawApp() +getKey() + + |