Files
terminal-portfolio/content.cpp
2025-10-18 00:15:18 -05:00

275 lines
7.0 KiB
C++

#include <ftxui/component/component.hpp>
#include <ftxui/component/component_base.hpp>
#include <ftxui/component/screen_interactive.hpp>
#include <ftxui/dom/elements.hpp>
#include <string>
#include <vector>
#include "content.hpp"
using namespace ftxui;
// New reusable styles (orange/red theme)
const auto theme_text_style = color(Color::OrangeRed1) | bold | dim;
const auto theme_border_style = border | color(Color::Red);
const auto theme_link_style = color(Color::RedLight) | underlined;
const auto theme_button_style = color(Color::Red) | bold;
const auto theme_button_active_style = color(Color::Yellow1) | bold;
// ------------------x
// Pages
// ------------------
Component MakeAboutPage() {
return Renderer([]() -> Element {
return vbox({
// Header section
vbox({
text("Keshav Anand") | color(Color::Blue) | bold | center,
text("Subtitle") | theme_text_style | center,
}) | theme_border_style,
separator(),
// Tags section
vbox({
text("insert_content") | theme_text_style | center,
}) | theme_border_style,
separator(),
// Focus areas
vbox({
text("Summ1") | color(Color::LightSkyBlue1) | bold,
}) | theme_border_style,
separator(),
// Current status
vbox({
text("Summ2") | color(Color::LightSkyBlue1) | bold,
}) | theme_border_style,
separator(),
// Location and contact
vbox({
text("Location") | theme_text_style | center,
text("Email") | theme_text_style | center,
text("Phone") | theme_link_style | center,
}) | theme_border_style,
}) | flex;
});
}
Component MakeProjectsPage() {
const std::vector<Project> projects = {
{"Insert Gibbersish"},
};
Component container = Container::Vertical({});
for (const Project& project : projects) {
Component card = Renderer([project]() -> Element {
Element title = text(project.title) | theme_text_style | bold;
Element desc = text(project.link) | color(Color::GreenYellow);
return vbox({
title,
desc
}) | theme_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({
// School section
vbox({
text("Education") | color(Color::LightGreen) | bold,
}) | theme_border_style,
separator(),
// Coursework section
vbox({
text("TODO: ADD AP scores, nonsense, etc.") | color(Color::LightGreen) | bold,
}) | theme_border_style,
separator(),
// Research section
vbox({
text("Research:") | color(Color::Blue) | bold,
text("GaitGuardian, LASER, TEG, etc.") | theme_text_style,
}) | theme_border_style,
}) | flex;
});
}
Component MakeWorkPage() {
struct WorkEntry {
std::string title;
std::string description;
};
const std::vector<WorkEntry> jobs = {
{"exp",
"desc"},
};
Component container = Container::Vertical({});
for (const WorkEntry& job : jobs) {
Component card = Renderer([job]() -> Element {
return vbox({
text(job.title) | color(Color::LightGreen) | bold,
text(job.description) | theme_text_style | dim,
}) | theme_border_style;
});
container->Add(card);
}
return Renderer(container, [container]() -> Element {
return vbox(container->Render()) | vscroll_indicator | yframe | flex;
});
}
Component MakeAwardsPage() {
const std::vector<std::string> awards = {
"Award 1", "Description 1",
};
Component container = Container::Vertical({});
// Process awards in pairs (title + description)
for (size_t i = 0; i < awards.size(); i += 2) {
const std::string& title = awards[i];
const std::string& desc = (i + 1 < awards.size()) ? awards[i + 1] : "";
Component card = Renderer([title, desc]() -> Element {
return vbox({
text(title) | color(Color::LightGreen) | bold,
text(desc) | theme_text_style | dim,
}) | theme_border_style;
});
container->Add(card);
}
return Renderer(container, [container]() -> Element {
return vbox(container->Render()) | vscroll_indicator | yframe | flex;
});
}
Component MakeSkillsPage() {
const std::string skills_content =
"Skills:\n";
return Renderer([skills_content]() -> Element {
return paragraph(skills_content) | theme_text_style | flex;
});
}
Component MakeContactPage() {
const std::string contact_info =
"Contact Me:\n";
return Renderer([contact_info]() -> Element {
return paragraph(contact_info) | theme_text_style | flex;
});
}
// Constructor implementation
PortfolioApp::PortfolioApp() {
// Build individual pages
about_page_ = MakeAboutPage();
projects_page_ = MakeProjectsPage();
education_page_ = MakeEducationPage();
work_page_ = MakeWorkPage();
awards_page_ = MakeAwardsPage();
skills_page_ = MakeSkillsPage();
contact_page_ = MakeContactPage();
// Add pages to vector
pages_.push_back(about_page_);
pages_.push_back(projects_page_);
pages_.push_back(education_page_);
pages_.push_back(work_page_);
pages_.push_back(awards_page_);
pages_.push_back(skills_page_);
pages_.push_back(contact_page_);
// Create navigation sidebar with orange/red styling
std::vector<std::string> labels = {"About", "Projects", "Education", "Work", "Awards", "Skills", "Contact"};
std::vector<Component> buttons;
for (int i = 0; i < (int)labels.size(); ++i) {
Component button = Button(labels[i], [&, i] { SwitchPage(i); })
| (i == current_page_ ? theme_button_active_style : theme_button_style);
buttons.push_back(button);
}
navigation_ = Container::Vertical(buttons);
// Initial layout
Component separator_component = Renderer([] { return separator(); });
Add(Container::Horizontal(Components{
navigation_,
separator_component,
pages_[current_page_]
}));
}
// SwitchPage method implementation
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_]
}));
}
// Render method implementation
Element PortfolioApp::Render() {
return hbox({
navigation_->Render() | theme_border_style,
separator(),
pages_[current_page_]->Render() | theme_border_style | flex
});
}
// OnEvent method implementation
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);
}