From 6383b52083efe5725c5944451c8132f015826a95 Mon Sep 17 00:00:00 2001 From: bckelley <> Date: Thu, 31 Oct 2024 15:14:36 -0500 Subject: [PATCH] init commit --- .gitignore | 5 ++ readme.md | 12 +++ src/css/style.css | 131 +++++++++++++++++++++++++++++ src/html/favicon.ico | Bin 0 -> 15086 bytes src/html/index.html | 46 +++++++++++ src/js/caret.js | 38 +++++++++ src/js/commands.js | 101 ++++++++++++++++++++++ src/js/main.js | 193 +++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 526 insertions(+) create mode 100644 .gitignore create mode 100644 readme.md create mode 100644 src/css/style.css create mode 100644 src/html/favicon.ico create mode 100644 src/html/index.html create mode 100644 src/js/caret.js create mode 100644 src/js/commands.js create mode 100644 src/js/main.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e072899 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +node_modules/ +.env +bckelleyResume.docx +app.js +package* \ No newline at end of file diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..8f2dd59 --- /dev/null +++ b/readme.md @@ -0,0 +1,12 @@ +# Terminal Portfolio + +A simple Express.js application for a terminal portfolio. + +## Installation + +Clone the repository and run: + +```bash +npm install +npm start +``` diff --git a/src/css/style.css b/src/css/style.css new file mode 100644 index 0000000..ff9f464 --- /dev/null +++ b/src/css/style.css @@ -0,0 +1,131 @@ +body { + margin: 0; + padding: 15px 20px; + min-height: 99%; + width: 100%; + min-width: 550px; + color: #519975; + background: #211D1B; + font-family: cursor, monospace; + overflow-x: hidden; +} +::selection { + color: #211830; + background-color: #519975; +} +::-moz-selection { + color: #211830; + background-color: #519975; +} +textarea { + left: -1000px; + position: absolute; +} +b { + font-weight: bold; + text-decoration: underline; +} +/* Cursor Start */ +.cursor { + font-size: 12px; + color: #73ABAD; + background-color: #73ABAD; + position: relative; + opacity: 1; + height: 1.5em; + width: 10px; + max-width: 10px; + transform: translateY(4px); + overflow: hidden; + text-indent: -5px; + display: inline-block; + text-decoration: blink; + animation: blinker 1s linear infinite; +} +@keyframes blinker { + 50% { + opacity: 0; + } +} +#command { + cursor: text; + height: 50px; + color: #73ABAD; +} +#liner { + line-height: 1.3em; + margin-top: -2px; + animation: show 0.5s ease forwards; + animation-delay: 1.2s; + opacity: 0; +} +#liner::before { + color: #519975; + content: "visitor@bckelley.com:~$"; +} +#liner.password::before { + content: "Password:"; +} +@keyframes show { + from { + opacity: 0; + } + to { + opacity: 1; + } +} +/* Cursor End */ +p { + display: block; + line-height: 1.3em; + margin: 0; + overflow: hidden; + white-space: nowrap; + margin: 0; + letter-spacing: 0.05em; + animation: typing 0.5s steps(30, end); +} +.no-animation { + animation: typing 0 steps(30, end); +} +.margin { + margin-left: 20px; +} +@keyframes typing { + from { + width: 0; + } + to { + width: 100%; + } +} +.index { + color: #DCDCCC; +} +.color2 { + color: #B89076; +} +.command { + color: #73ABAD; + text-shadow: 0 0 5px #73ABAD; +} +.error { + color: #B89076; +} +.white { + color: #fff; +} +.inherit, +a { + color: #9C8394; +} +a { + text-decoration: inherit; +} +a:hover { + background: #73ABAD; + color: #211830; +} +a:focus { + outline: 0; +} \ No newline at end of file diff --git a/src/html/favicon.ico b/src/html/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..b62d3cf43fe14ff2c3ece36ce4a54056604f904d GIT binary patch literal 15086 zcmZQzU}RusFfd>M(h3YKR2dk|7#I+I0S1P9Krxtn1`7j28&H7;NDUAt05M1(2xxGE zDHOuV$>skj9u0%hG%%V5M$^D(8qjRC{KI}-`!Dxd-9M%Yc7I7t6Y?`n|FGQC`pfiK z^A9yK+b!+C>MfRk@VUn_!r?E&E6x9K{8ID3aVqhC(5bNg1J{de4i(uJQT8~)RIA1c z(|!{CAUE3-Q$H2m4hkEsS}UA!VC(0E8vZc5iS&bUx-HG!Zxi5%GyFkmOTW+tyBmn~ zgI=-qAK@Jae+2g!{H7)r-D>#9B$>FhY*0X%AMoWdddV5&*-(_0=;cm)_88<2eLooH z*be!40Q!NVJdH1o=_O~FjoS|( zc=|7c-0gV#UW483`1-zs-0k}K#vTT_+iiXEj9(3Mw}bMzHm>o*A>ek9`z^4I-wqMC z!^&BWCd)r;H?{wAod=GeCl2oN9p>gydUW1rG!2ZVfzdQD^3njxVxUnD-9rGhPD=rZ z9e^0VP7An(3muH+&5@Tk2Wy-w%rO0<-ey5?jM^s9@vp>Mqrc+ojQ)^{L2DVX`CoP( zVvU2~eto>-Cm3@yu=NN;(lQH7Fx;Rt(Hvzi5uY0r z9Kg)tKctVECI`R`0tW_x8-QgJa=zCkkdI*DM=csu7NFQ)hCd%u%U+N7xeCcVyuF&4*t0(bL~(^^X7@?MAPE>1ns}1l0BiJ?#di zSLF5=z3qnO7x`JHpf(NO_6bbwC_UP58V+dyeLR5Pe9$-raH|=3tO7nx!HDUKVG-8Q o{vonoh*?{YtRB_|Llz^IJzUJ7#2+I~FR5u{u&Ku^5l9mO07=eqJOBUy literal 0 HcmV?d00001 diff --git a/src/html/index.html b/src/html/index.html new file mode 100644 index 0000000..68f74d2 --- /dev/null +++ b/src/html/index.html @@ -0,0 +1,46 @@ + + + + + + + + + + + + bckelley | Terminal + + + + + +
+ +
+
+ +
+ +
+
+ + + + + + diff --git a/src/js/caret.js b/src/js/caret.js new file mode 100644 index 0000000..c5112b2 --- /dev/null +++ b/src/js/caret.js @@ -0,0 +1,38 @@ +function $(elid) { + return document.getElementById(elid); + } + +var cursor; +window.onload = init; + +function init() { + cursor = $("cursor"); + cursor.style.left = "0px"; +} + +function nl2br(txt) { + return txt.replace(/\n/g, ''); +} + +function typeIt(from, e) { + e = e || window.event; + var w = $("typer"); + var tw = from.value; + if (!pw){ + w.innerHTML = nl2br(tw); + } +} + +function moveIt(count, e) { + e = e || window.event; + var keycode = e.keyCode || e.which; + if (keycode == 37 && parseInt(cursor.style.left) >= (0 - ((count - 1) * 10))) { + cursor.style.left = parseInt(cursor.style.left) - 10 + "px"; + } else if (keycode == 39 && (parseInt(cursor.style.left) + 10) <= 0) { + cursor.style.left = parseInt(cursor.style.left) + 10 + "px"; + } +} + +function alert(txt) { + console.log(txt); +} \ No newline at end of file diff --git a/src/js/commands.js b/src/js/commands.js new file mode 100644 index 0000000..c3a048a --- /dev/null +++ b/src/js/commands.js @@ -0,0 +1,101 @@ +var youtube = ""; +var twitter = ""; +var instagram = ""; +var threads = ""; +var github = "https://github.com/bckelley/"; +var linkedin = "https://www.linkedin.com/in/bckelley2/"; +var password = "phpRulez"; +var email = 'mailto:admin@bradonckelley.me'; + +whois = [ + "
", + "Hey! My name is Bradon 👋 and I am a back-end developer with a passion for PHP and technology.", + "I have 12 of experience and have worked on projects like my SimplePHPDB which can read about on github.", + "You can connect with me on linkedin or check out my work on github", + "
" +]; + +whoami = [ + "
", + "The paradox of “Who am I?” is a labyrinth with no map, yet we tirelessly", + "explore its winding paths. Each step reveals a new facet of ourselves, a", + "reflection in the ever-shifting mirror of experience. And so, the journey", + "becomes the answer, the quest for self-discovery a tapestry woven from the", + "threads of existence.", + "
" +]; + +social = [ + "
", + (youtube !== "") ? 'youtube youtube/' + "" : '', + (twitter !== "") ? 'twitter twitter/' + '' : '', + (linkedin !== "") ? 'linkedin linkedin/bckelley' + "" : '', + (instagram !== "") ? 'instagram instagram/' + '' : '', + (threads !== "") ? 'threads threads/' + '' : '', + (github !== "") ? 'github github/bckelley' + "" : '', + "
" +]; + +secret = [ + "
", + "sudo We trust you have received the usual lecture from the local", + " System Administrator. It usually boils down to these three things: ", + " #1) Respect the privacy of others. ", + " #2) Think before you type. ", + " #3) With great power comes great responsibility. ", + "
" +]; + +projects = [ + "
", + "Still curating... most projects are offline, on GitHub, or confidential.", + (github !== "") ? '[ github/todo-list ]: github/bckelley/todo-list' + "" : '', + (github !== "") ? '[ github/RouteEaseMVC ]: github/bckelley/TouteEaseMVC' + "" : '', + (github !== "") ? '[ github/SimplePHPDB ]: github/bckelley/SimplePHPDB' + "" : '', +// (github !== "") ? '[ github/ ]: github/bckelley/' + "" : '', + "
" +]; + +help = [ + "
", + 'whois Who is bckelley?', + 'whoami Who are you?', + (youtube !== "")?'video View YouTube videos': '', + 'social Display social networks', + 'secret Find the password', + 'projects View coding projects', + 'history View command history', + 'help You obviously already know what this does', + 'email Do not email me', + 'clear Clear terminal', + 'banner Display the header', + "
", +]; + +license = [ + '
', + '

bckelley Terminal Portfolio by bckelley is licensed under
Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International

' +]; + + +banner = [ + 'Bradon Kelley (BK) Not A Corporation. All rights reserved.', + ' ', + ' ,dPYb, ,dPYb, ,dPYb, ,dPYb, ', + ' IP\'`Yb IP\'`Yb IP\'`Yb IP\'`Yb ', + ' I8 8I I8 8I I8 8I I8 8I ', + ' I8 8\' I8 8bgg, I8 8\' I8 8\' ', + ' I8 dP ,gggg, I8 dP" "8 ,ggg, I8 dP I8 dP ,ggg, gg gg ', + ' I8dP 88gg dP" "Yb I8d8bggP" i8" "8i I8dP I8dP i8" "8i I8 8I ', + ' I8P 8I i8\' I8P\' "Yb, I8, ,8I I8P I8P I8, ,8I I8, ,8I ', + ' ,d8b, ,8I ,d8,_ _,d8 `Yb, `YbadP\' ,d8b,_ ,d8b,_ `YbadP\' ,d8b, ,d8I ', + ' 8P\'"Y88P"\' P""Y8888PP88P Y8888P"Y8888P\'"Y888P\'"Y88888P"Y888P""Y88P"888 ', + ' ,d8I\' ', + ' ,dP\'8I ', + ' ,8" 8I ', + ' I8 8I ', + ' `8, ,8I ', + ' `Y8P\' ', + 'Welcome to my interactive web terminal.', + 'For a list of available commands, type \'help\'.', +]; \ No newline at end of file diff --git a/src/js/main.js b/src/js/main.js new file mode 100644 index 0000000..e10514a --- /dev/null +++ b/src/js/main.js @@ -0,0 +1,193 @@ +var before = document.getElementById("before"); +var liner = document.getElementById("liner"); +var command = document.getElementById("typer"); +var textarea = document.getElementById("texter"); +var terminal = document.getElementById("terminal"); + +var git = 0; +var pw = false; +let pwd = false; +var commands = []; + +setTimeout(function() { + loopLines(banner, "", 80); + textarea.focus(); +}, 100); + +window.addEventListener("keyup", enterKey); + +console.log( + "%cYou hacked my password!😠", + "color: #04ff00; font-weight: bold; font-size: 24px;" +); +console.log("%cPassword: '" + password + "' - I wonder what it does?🤔", "color: grey"); + +//init +textarea.value = ""; +command.innerHTML = textarea.value; + +function enterKey(e) { + if (e.keyCode == 181) { + document.location.reload(true); + } + if (pw) { + let et = "*"; + let w = textarea.value.length; + command.innerHTML = et.repeat(w); + if (textarea.value === password) { + pwd = true; + } + if (pwd && e.keyCode == 13) { + loopLines(secret, "color2 margin", 120); + command.innerHTML = ""; + textarea.value = ""; + pwd = false; + pw = false; + liner.classList.remove("password"); + } else if (e.keyCode == 13) { + addLine("Wrong password", "error", 0); + command.innerHTML = ""; + textarea.value = ""; + pw = false; + liner.classList.remove("password"); + } + } else { + if (e.keyCode == 13) { + commands.push(command.innerHTML); + git = commands.length; + addLine("visitor@bckelley.com:~$ " + command.innerHTML, "no-animation", 0); + commander(command.innerHTML.toLowerCase()); + command.innerHTML = ""; + textarea.value = ""; + } + if (e.keyCode == 38 && git != 0) { + git -= 1; + textarea.value = commands[git]; + command.innerHTML = textarea.value; + } + if (e.keyCode == 40 && git != commands.length) { + git += 1; + if (commands[git] === undefined) { + textarea.value = ""; + } else { + textarea.value = commands[git]; + } + command.innerHTML = textarea.value; + } + } +} + +function commander(cmd) { + switch (cmd.toLowerCase()) { + case "help": + loopLines(help, "color2 margin", 80); + break; + case "whois": + loopLines(whois, "color2 margin", 80); + break; + case "whoami": + loopLines(whoami, "color2 margin", 80); + break; + case "video": + addLine("Opening YouTube...", "color2", 80); + newTab(youtube); + break; + case "sudo": + addLine("Oh no, you're not admin...", "color2", 80); + setTimeout(function() { + window.open('https://youtu.be/uRGljemfwUE?si=V-SJLK5v-Dj9FIE3'); + }, 1000); + break; + case "social": + loopLines(social, "color2 margin", 80); + break; + case "secret": + liner.classList.add("password"); + pw = true; + break; + case "projects": + loopLines(projects, "color2 margin", 80); + break; + case "password": + addLine(" Lol! You're joking, right? You\'re gonna have to try harder than that!😂", "error", 100); + break; + case "history": + addLine("
", "", 0); + loopLines(commands, "color2", 80); + addLine("
", "command", 80 * commands.length + 50); + break; + case "email": + addLine(`Opening ${email}...`, "color2", 80); + newTab(email); + break; + case "clear": + setTimeout(function() { + terminal.innerHTML = ''; + before = document.getElementById("before"); + }, 1); + break; + case "banner": + loopLines(banner, "", 80); + break; + // socials + case "youtube": + addLine("Opening YouTube...", "color2", 80); + newTab(youtube); + break; + case "twitter": + addLine("Opening Twitter...", "color2", 0); + newTab(twitter); + break; + case "linkedin": + addLine("Opening LinkedIn...", "color2", 0); + newTab(linkedin); + break; + case "instagram": + addLine("Opening Instagram...", "color2", 0); + newTab(instagram); + break; + case "github": + addLine("Opening GitHub...", "color2", 0); + newTab(github); + break; + case "license": + loopLines(license, "", 80); + break; + default: + addLine("Command not found. For a list of commands, type 'help'.", "error", 100); + break; + } +} + +function newTab(link) { + setTimeout(function() { + window.open(link, "_blank"); + }, 500); +} + +function addLine(text, style, time) { + var t = ""; + for (let i = 0; i < text.length; i++) { + if (text.charAt(i) == " " && text.charAt(i + 1) == " ") { + t += "  "; + i++; + } else { + t += text.charAt(i); + } + } + setTimeout(function() { + var next = document.createElement("p"); + next.innerHTML = t; + next.className = style; + + before.parentNode.insertBefore(next, before); + + window.scrollTo(0, document.body.offsetHeight); + }, time); +} + +function loopLines(name, style, time) { + name.forEach(function(item, index) { + addLine(item, style, index * time); + }); +}