diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d3ed558 --- /dev/null +++ b/.gitignore @@ -0,0 +1,88 @@ +# ------------------------------------------------------ +# Build folders (your own build directories) +# ------------------------------------------------------ +linuxbuild/ +macbuild/ +winbuild/ + +# External + + +ftxui/ + +# If you ever add a generic build folder: +build/ +build-*/ + +# ------------------------------------------------------ +# CMake generated files +# ------------------------------------------------------ +CMakeFiles/ +CMakeCache.txt +cmake_install.cmake +Makefile +install_manifest.txt + +# ninja build +.ninja_log +.ninja_deps +rules.ninja + +# ------------------------------------------------------ +# Compiled object files / binaries +# ------------------------------------------------------ +*.o +*.obj +*.lo +*.la +*.a +*.lib +*.so +*.dll +*.dylib +*.exe +*.out +*.app +*.pch + +# ------------------------------------------------------ +# Logs + temporary files +# ------------------------------------------------------ +*.log +*.tmp +*.temp + +# ------------------------------------------------------ +# OS-generated crap +# ------------------------------------------------------ +# macOS +.DS_Store +.AppleDouble +.LSOverride + +# Windows +Thumbs.db +ehthumbs.db +Desktop.ini + +# Linux +*~ + +# ------------------------------------------------------ +# Editor / IDE files +# ------------------------------------------------------ +.vscode/ +.idea/ +*.code-workspace + +# ------------------------------------------------------ +# Shell script caches +# ------------------------------------------------------ +*.swp +*.swo + +# ------------------------------------------------------ +# Keep these files (GitHub Pages) +# ------------------------------------------------------ +!index.html +!CNAME \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..8e5f96f --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,24 @@ +cmake_minimum_required(VERSION 3.16) +project(PortfolioApp LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +# Add local FTXUI directory +add_subdirectory(ftxui) + +# Add your source files (adjust paths if needed) +add_executable(portfolio + main.cpp + content.cpp +) + +# Link with FTXUI +target_link_libraries(portfolio + PRIVATE + ftxui::screen + ftxui::dom + ftxui::component +) + diff --git a/CNAME b/CNAME new file mode 100644 index 0000000..faf8daa --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +terminalportfolio.keshavanand.net \ No newline at end of file diff --git a/commands.sh b/commands.sh new file mode 100644 index 0000000..329b734 --- /dev/null +++ b/commands.sh @@ -0,0 +1,65 @@ +#!/bin/bash + +#macos + +cd ~/Downloads/Code/Terminal +rm -rf macbuild +mkdir macbuild +cd macbuild +cmake -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" .. +make + + + +#Linux + +cd ~/Downloads/Code/Terminal +rm -rf linuxbuild +mkdir linuxbuild +cd linuxbuild + +docker run --rm -v "$(pwd)/..":/src -w /src gcc:latest bash -c " +apt-get update && apt-get install -y cmake make +mkdir -p build && cd build +cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_EXE_LINKER_FLAGS='-static' .. +make +cd .. +mv build linuxbuild/ +" + +#Linux Test + +cd ~/Downloads/Code/Terminal + +docker run --rm -v "$(pwd)/linuxbuild":/build -w /build --platform linux/amd64 ubuntu:22.04 bash -c " +apt-get update && apt-get install -y libstdc++6 +./build/portfolio +" + +#Windows: + +cd ~/Downloads/Code/Terminal +rm -rf winbuild +mkdir winbuild + +# Download Dockcross helper +docker run --rm dockcross/windows-static-x64 > ./winbuild/dockcross-windows +chmod +x ./winbuild/dockcross-windows + +# Build Windows binary inside winbuild +# Note: we mount the repo root (current folder) as /work +./winbuild/dockcross-windows bash -c " +mkdir -p /work/winbuild/build +cd /work/winbuild/build +cmake -DCMAKE_BUILD_TYPE=Release -S /work -B . +make +cp portfolio.exe /work/winbuild/ +" + +#Windows Test (requires Wine) + +cd ~/Downloads/Code/Terminal + +docker run --rm -v "$(pwd)/winbuild":/winbuild -w /winbuild --platform linux/amd64 \ + scottyhardy/docker-wine:latest wine64 build/portfolio.exe + diff --git a/content.cpp b/content.cpp new file mode 100644 index 0000000..f79fd5f --- /dev/null +++ b/content.cpp @@ -0,0 +1,223 @@ +#include +#include +#include +#include +#include +#include +#include "content.hpp" + +using namespace ftxui; + +// Hacker-style reusable styles +const auto hacker_text_style = color(Color::Green) | bold | dim; +const auto hacker_border_style = border | color(Color::Green); +const auto hacker_link_style = color(Color::LightGreen) | underlined; +const auto hacker_button_style = color(Color::Green) | bold; +const auto hacker_button_active_style = color(Color::LightGreen) | bold; + +// ------------------ +// Pages +// ------------------ + +Component MakeAboutPage() { + return Renderer([]() -> Element { + return vbox({ + vbox({ + text("Keshav Anand") | color(Color::LightGreen) | bold | center, + text("Student Researcher | ML + Robotics Developer | CS + Math Enthusiast") | hacker_text_style | center, + }) | hacker_border_style, + + }) | flex; + }); +} + +Component MakeProjectsPage() { + const std::vector> projects = { + {"🧠 GaitGuardian: IMU Processing for Parkinson’s Disease (2024–Present)", + "β€’ Hybrid biLSTM + CNN model for Freezing of Gait prediction\n" + "β€’ Signal segmentation reduces subject dependence\n" + "β€’ State-of-the-art accuracy, end-to-end functionality"}, + {"πŸ”₯ TEG-Powered Self-Stirring Device (2023–2024)", + "β€’ Built thermal energy harvesting prototype for self-stirring cookware\n" + "β€’ Developed mechanical + electrical integration\n" + "β€’ Won 1st at Dallas Fair, ISEF Finalist"}, + {"πŸ€– FTC Technical Turbulence (23344) β€” Lead Software Developer (2023–Present)", + "β€’ Custom inverse kinematics, pathing, and Computer Vision autonomy\n" + "β€’ Top-30 globally for software performance, FTC State Finalist"}, + }; + + Component container = Container::Vertical({}); + for (auto& p : projects) { + Component card = Renderer([p]() -> Element { + return vbox({ + text(p.first) | color(Color::LightGreen) | bold, + paragraph(p.second) | hacker_text_style | dim, + }) | hacker_border_style; + }); + container->Add(card); + } + + return Renderer(container, [container]() -> Element { + return vbox(container->Render()) | vscroll_indicator | yframe | flex; + }); +} + +Component MakeEducationPage() { + return Renderer([]() -> Element { + return vbox({ + vbox({ + text("🏫 Plano East Senior High School (2023–2027)") | color(Color::LightGreen) | bold, + text("STEM & Multidisciplinary Endorsement") | hacker_text_style, + text("GPA: 4.73 | Rank: 1/1273 | SAT: 1550") | hacker_text_style, + }) | hacker_border_style, + + separator(), + + vbox({ + text("πŸ“š Current Coursework:") | color(Color::LightGreen) | bold, + text("β€’ AP Chemistry") | hacker_text_style, + text("β€’ AP Physics I") | hacker_text_style, + text("β€’ Digital Electronics") | hacker_text_style, + text("β€’ American Studies (AP US History + AP English Language)") | hacker_text_style, + text("β€’ Calculus III (via Collin College)") | hacker_text_style, + }) | hacker_border_style, + }) | flex; + }); +} + +Component MakeWorkPage() { + const std::vector> activities = { + {"πŸ§ͺ Vice President, LASER (Science Fair Organization)", + "Guiding and mentoring 120+ students in research and experimentation"}, + {"πŸ’» Technology Officer, National Honor Society", + "Developed and maintained React-based management portal for 1000+ members"}, + {"🏏 Founder & Captain, Plano East Cricket Club", + "Established first school tapeball cricket team; coached and led events"}, + {"🎢 Indian Film Music Performer", + "Bass guitar & keyboard player in charity concerts; arrangement and production"}, + }; + + Component container = Container::Vertical({}); + for (auto& a : activities) { + Component card = Renderer([a]() -> Element { + return vbox({ + text(a.first) | color(Color::LightGreen) | bold, + text(a.second) | hacker_text_style | dim, + }) | hacker_border_style; + }); + container->Add(card); + } + + return Renderer(container, [container]() -> Element { + return vbox(container->Render()) | vscroll_indicator | yframe | flex; + }); +} + +Component MakeAwardsPage() { + const std::vector> awards = { + {"πŸ₯‡ Thermoelectric Generator Research Project (2024)", + "Dallas Fair: 1st in Engineering | USAF Recognition | USMA Best SI Units\nISEF Finalist"}, + {"πŸ₯ˆ GaitGuardian ML Research (2025)", + "Dallas Fair: 1st in Systems Software, Grand Prize Runner-Up\nISEF Finalist | 3rd in Robotics & Intelligent Systems"}, + {"πŸ… National Speech & Debate (2025)", + "Impromptu Quarterfinalist at District and State Level"}, + }; + + Component container = Container::Vertical({}); + for (auto& a : awards) { + Component card = Renderer([a]() -> Element { + return vbox({ + text(a.first) | color(Color::LightGreen) | bold, + paragraph(a.second) | hacker_text_style | dim, + }) | hacker_border_style; + }); + container->Add(card); + } + + return Renderer(container, [container]() -> Element { + return vbox(container->Render()) | vscroll_indicator | yframe | flex; + }); +} + +Component MakeSkillsPage() { + const std::string skills = + "πŸ’» Programming Languages:\n" + " Java, Python, Bash, C++ (Arduino), Kotlin (FTC), limited HTML/CSS/JS\n\n" + "🧠 Applications:\n" + " Machine Learning, Signal Processing, TensorFlow, Computer Vision\n\n" + "βš™οΈ Miscellaneous:\n" + " Public Speaking, CAD, PCB Design, Electrical Systems, Competition Math"; + + return Renderer([skills]() -> Element { + return paragraph(skills) | hacker_text_style | flex; + }); +} + +Component MakeContactPage() { + const std::string contact_info = + "πŸ“« Email: keshavanandofficial@gmail.com\n" + "πŸ”— LinkedIn: linkedin.com/in/keshavganand\n" + "πŸ’» GitHub: github.com/keshavanandcode\n" + "🌐 Resume: resume.keshavanand.net\n" + "πŸ“ DFW Metroplex, Texas\n\n" + "Updated: November 2025"; + + return Renderer([contact_info]() -> Element { + return paragraph(contact_info) | hacker_text_style | flex; + }); +} + +// Constructor implementation +PortfolioApp::PortfolioApp() { + about_page_ = MakeAboutPage(); + projects_page_ = MakeProjectsPage(); + education_page_ = MakeEducationPage(); + work_page_ = MakeWorkPage(); + awards_page_ = MakeAwardsPage(); + skills_page_ = MakeSkillsPage(); + contact_page_ = MakeContactPage(); + + pages_ = {about_page_, projects_page_, education_page_, + work_page_, awards_page_, skills_page_, contact_page_}; + + std::vector labels = {"About", "Projects", "Education", "Activities", "Awards", "Skills", "Contact"}; + + std::vector buttons; + for (int i = 0; i < (int)labels.size(); ++i) { + Component button = Button(labels[i], [&, i] { SwitchPage(i); }) + | (i == current_page_ ? hacker_button_active_style : hacker_button_style); + buttons.push_back(button); + } + + navigation_ = Container::Vertical(buttons); + Component separator_component = Renderer([] { return separator(); }); + + Add(Container::Horizontal(Components{navigation_, separator_component, pages_[current_page_]})); +} + +void PortfolioApp::SwitchPage(int index) { + current_page_ = index; + DetachAllChildren(); + Component separator_component = Renderer([] { return separator(); }); + Add(Container::Horizontal(Components{navigation_, separator_component, pages_[current_page_]})); +} + +Element PortfolioApp::Render() { + return hbox({ + navigation_->Render() | hacker_border_style, + separator(), + pages_[current_page_]->Render() | hacker_border_style | flex + }); +} + +bool PortfolioApp::OnEvent(Event event) { + if (event == Event::ArrowRight) { + SwitchPage((current_page_ + 1) % pages_.size()); + return true; + } + if (event == Event::ArrowLeft) { + SwitchPage((current_page_ - 1 + pages_.size()) % pages_.size()); + return true; + } + return ComponentBase::OnEvent(event); +} diff --git a/content.hpp b/content.hpp new file mode 100644 index 0000000..cdb0971 --- /dev/null +++ b/content.hpp @@ -0,0 +1,111 @@ +#pragma once +#include +#include +#include +#include +#include +#include + +// ------------------ +// Structs +// ------------------ +struct Project { + std::string title; + std::string link; // Leave empty if no link +}; + +// ------------------ +// PageFactory Functions +// + +// ------------------ +/** + * Creates the About page component + * @return Component containing personal introduction and focus areas + */ +ftxui::Component MakeAboutPage(); + +/** + * Creates the Projects page component + * @return Component displaying list of projects with links + */ +ftxui::Component MakeProjectsPage(); + +/** + * Creates the Education page component + * @return Component showing educational background and achievements + */ +ftxui::Component MakeEducationPage(); + +/** + * Creates the Work page component + * @return Component displaying work experience and competitions + */ +ftxui::Component MakeWorkPage(); + +/** + * Creates the Awards page component + * @return Component displaying awards, competitions, and achievements + */ +ftxui::Component MakeAwardsPage(); + +/** + * Creates the Skills page component + * @return Component showing technical skills and expertise + */ +ftxui::Component MakeSkillsPage(); + +/** + * Creates the Contact page component + * @return Component with contact information + */ +ftxui::Component MakeContactPage(); + +// ------------------ +// Main Application Class +// ------------------ +/** + * Main portfolio application class that manages navigation and page switching + * Inherits from ftxui::ComponentBase to provide custom rendering and event handling + */ +class PortfolioApp : public ftxui::ComponentBase { +public: + /** + * Constructor - initializes all pages and navigation + */ + PortfolioApp(); + + /** + * Switch to a specific page by index + * @param index The page index to switch to (0-6) + */ + void SwitchPage(int index); + + /** + * Render the current application state + * @return Element representing the full UI layout + */ + ftxui::Element Render(); + + /** + * Handle keyboard events for navigation + * @param event The keyboard event to process + * @return true if event was handled, false otherwise + */ + bool OnEvent(ftxui::Event event) override; + +private: + int current_page_ = 0; // Currently active page index + + // UI Components + ftxui::Component navigation_; // Navigation sidebar + ftxui::Component about_page_; // About page component + ftxui::Component projects_page_; // Projects page component + ftxui::Component education_page_; // Education page component + ftxui::Component work_page_; // Work page component + ftxui::Component awards_page_; // Awards page component + ftxui::Component skills_page_; // Skills page component + ftxui::Component contact_page_; // Contact page component + + std::vector pages_; // Vector of all page components +}; diff --git a/index.html b/index.html new file mode 100644 index 0000000..c9a5bf4 --- /dev/null +++ b/index.html @@ -0,0 +1,518 @@ + + + + + +Terminal Portfolio + + + + + + + + +
+ +
+
+$ Detecting your OS...
+    
+
+ +
+
+ + +
+
+ +
+
+ + +
+ +
+ + +
Run at Your Own Risk
+ + + +
+ +
+
+ +
    +
  1. + Terminal Command Execution: + The command you copy downloads a platform-specific script: +
      +
    • .sh for Mac/Linux
    • +
    • .bat for Windows
    • +
    + This script is hosted on my GitHub and automatically runs the corresponding binary. +
  2. + +
  3. + Binary Execution: + The binary is compiled in C++ separately for each OS and controls the standard input/output of your terminal to create a clean, interactive interface. +
  4. + +
  5. + FTXUI Integration: + It leverages the FTXUI library to render a web-like interactive menu directly inside your terminal, making navigation and presentation of my portfolio terminal-friendly but visually elegant. +
  6. + +
  7. + Cross-Platform Support: + Each OS has its own binary to ensure consistent behavior on Windows, Mac, and Linux. +
  8. +
+ +

+ + View Source on GitHub + +

+
+
+
+
+ + + + \ No newline at end of file diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..aef7def --- /dev/null +++ b/main.cpp @@ -0,0 +1,13 @@ +#include "content.hpp" +#include +#include +#include +#include +#include + +int main() { + ftxui::ScreenInteractive screen = ftxui::ScreenInteractive::Fullscreen(); + ftxui::Component app = std::make_shared(); + screen.Loop(app); + return 0; +} diff --git a/run-linux.sh b/run-linux.sh new file mode 100644 index 0000000..76d9e9f --- /dev/null +++ b/run-linux.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +# Download the Linux executable +curl -L https://github.com/KeshavAnandCode/Terminal/releases/download/v2.0/portfolio-linux -o /tmp/portfolio + +# Make it executable +chmod +x /tmp/portfolio + +# Run it +/tmp/portfolio + +# Clean up +rm /tmp/portfolio \ No newline at end of file diff --git a/run-mac.sh b/run-mac.sh new file mode 100644 index 0000000..acfbfd7 --- /dev/null +++ b/run-mac.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +# Download the macOS executable +curl -L https://github.com/KeshavAnandCode/Terminal/releases/download/v2.0/portfolio-mac -o /tmp/portfolio + +# Make it executable +chmod +x /tmp/portfolio + +# Run it +/tmp/portfolio + +# Clean up +rm /tmp/portfolio \ No newline at end of file diff --git a/run-windows.bat b/run-windows.bat new file mode 100644 index 0000000..78b1055 --- /dev/null +++ b/run-windows.bat @@ -0,0 +1,13 @@ +@echo off +setlocal + +:: Download the Windows executable +powershell -Command "Invoke-WebRequest -Uri 'https://github.com/KeshavAnandCode/Terminal/releases/download/v2.0/portfolio-windows' -OutFile '%TEMP%\\portfolio.exe'" + +:: Run the executable +"%TEMP%\portfolio.exe" + +:: Clean up +del "%TEMP%\portfolio.exe" + +endlocal \ No newline at end of file diff --git a/terminalOneLiners.txt b/terminalOneLiners.txt new file mode 100644 index 0000000..0b44490 --- /dev/null +++ b/terminalOneLiners.txt @@ -0,0 +1,3 @@ +/bin/bash -c "$(curl -fsSL https://terminalportfolio.keshavanand.net/run-mac.sh)" for Mac +/bin/bash -c "$(curl -fsSL https://terminalportfolio.keshavanand.net/run-linux.sh)" for linux +iwr https://terminalportfolio.keshavanand.net/run-windows.bat -OutFile \$env:TEMP\run-windows.bat; Start-Process \$env:TEMP\run-windows.bat -Wait \ No newline at end of file