5-4 - convert to next.js

This commit is contained in:
Charlotte Croce 2025-05-04 21:41:58 -04:00
parent 432a72b2f2
commit a23cb6f09c
32 changed files with 9050 additions and 371 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
node_modules
.next

View file

@ -1,113 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Charlotte Croce - Cybersecurity student and developer">
<title>Charlotte Croce - ./charlotte.sh</title>
<link rel="stylesheet" href="style.css">
<script src="https://unpkg.com/lucide@latest/dist/umd/lucide.min.js"></script>
</head>
<body>
<a href="#main-content" class="skip-link">Skip to main content</a>
<header>
<nav aria-label="Main navigation">
<div class="container">
<a href="/" class="logo">./charlotte.sh</a>
<button class="menu-toggle" aria-expanded="false" aria-controls="primary-menu" aria-label="Toggle menu">
<i data-lucide="menu" id="menu-icon" aria-hidden="true"></i>
<i data-lucide="x" id="close-icon" style="display: none;" aria-hidden="true"></i>
</button>
<ul class="nav-links" id="primary-menu">
<li><a href="https://github.com/charlottecroce" target="_blank" rel="noopener noreferrer">GitHub <i
data-lucide="external-link" class="icon-small" aria-hidden="true"></i><span
class="visually-hidden">(opens in new tab)</span></a></li>
<li><a href="https://git.charlotte.sh" target="_blank" rel="noopener noreferrer">Forgejo<i
data-lucide="external-link" class="icon-small" aria-hidden="true"></i><span
class="visually-hidden">(opens in new tab)</span></a></li>
<li><a href="https://linkedin.com/in/charlottecroce" target="_blank" rel="noopener noreferrer">LinkedIn <i
data-lucide="external-link" class="icon-small" aria-hidden="true"></i><span
class="visually-hidden">(opens in new tab)</span></a></li>
<button class="theme-toggle" aria-label="Toggle dark mode">
<i data-lucide="moon" id="moon-icon" aria-hidden="true"></i>
<i data-lucide="sun" id="sun-icon" style="display: none;" aria-hidden="true"></i>
</button>
</li>
</ul>
</div>
</nav>
</header>
<main id="main-content">
<div class="container">
<section class="intro">
<h1>Hi! I'm Charlotte</h1>
<h2>About Me</h2>
<p>I'm a cybersecurity student from the Northeast USA. I currently work as a security engineer at the Leahy
Center in
Burlington, VT.</p>
<p>Most of my coding projects are hosted on my Forgejo server at <a href="https://git.charlotte.sh/"
target="_blank" rel="noopener noreferrer">git.charlotte.sh<i data-lucide="external-link" class="icon-small"
aria-hidden="true"></i><span class="visually-hidden">(opens in new tab)</span></a></p>
<p>Hiring? you can my find my resume <a href="resume.html">here</a></p>
</section>
<section class="projects">
<h2>My Projects</h2>
<div class="project-grid">
<article class="project">
<h3>Fylgja SOC</h3>
<p>A domain-specific language (DSL) for managing an ELK SIEM. Includes a CLI and SlackBot interface</p>
<a href="https://git.charlotte.sh/lotte/fylgja" target="_blank" rel="noopener noreferrer">Source Code<i
data-lucide="external-link" class="icon-small" aria-hidden="true"></i><span
class="visually-hidden">(opens in new tab)</span></a>
</article>
<article class="project">
<h3>Champlain Tech Journals</h3>
<p>Notes, code, and lab write-ups from my Champlain College courses</p>
<a href="https://git.charlotte.sh/lotte/ChamplainTechJournals" target="_blank"
rel="noopener noreferrer">Source Code<i data-lucide="external-link" class="icon-small"
aria-hidden="true"></i><span class="visually-hidden">(opens in new tab)</span></a>
</article>
<article class="project">
<h3>Nøkken Health</h3>
<p>A Flutter app to track and analyze health data</p>
<a href="https://git.charlotte.sh/lotte/nokken" target="_blank" rel="noopener noreferrer">Source Code<i
data-lucide="external-link" class="icon-small" aria-hidden="true"></i><span
class="visually-hidden">(opens in new tab)</span></a>
</article>
</div>
</section>
</div>
</main>
<footer>
<div class="container">
<ul class="social-links">
<li><a href="https://github.com/charlottecroce" target="_blank" rel="noopener noreferrer">GitHub</a></li>
<li><a href="https://git.charlotte.sh/lotte" target="_blank" rel="noopener noreferrer">Forgejo</a></li>
<li><a href="https://linkedin.com/in/charlottecroce" target="_blank" rel="noopener noreferrer">LinkedIn</a></li>
<li><a href="https://hachyderm.io/@charlotte200" target="_blank" rel="noopener noreferrer me">Mastodon</a></li>
<li><a href="https://bookwyrm.social/user/lottie" target="_blank" rel="noopener noreferrer">BookWyrm</a></li>
<li><a href="https://rss.charlotte.sh" target="_blank" rel="noopener noreferrer"><i data-lucide="rss" class="icon-small" aria-hidden="true"></i><span class="visually-hidden">FreshRSS</span></a></li>
</ul>
<p>&copy;<span id="current-year"></span> Charlotte Croce</p>
<p class="theme-note">If you like the colors of this website, check out my <a
href="https://marketplace.visualstudio.com/items?itemName=charlotte-dev.fruitbasket-theme" target="_blank"
rel="noopener noreferrer">VS Code Theme<i data-lucide="external-link" class="icon-small"
aria-hidden="true"></i><span class="visually-hidden">(opens in new tab)</span></a></p>
</div>
</footer>
<script src="script.js"></script>
</body>
</html>

5
next-env.d.ts vendored Normal file
View file

@ -0,0 +1,5 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.

16
next.config.js Normal file
View file

@ -0,0 +1,16 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: '**',
},
],
},
experimental: {
optimizeCss: true,
},
}
module.exports = nextConfig

7185
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

28
package.json Normal file
View file

@ -0,0 +1,28 @@
{
"name": "charlotte-portfolio",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"lucide-react": "^0.454.0",
"next": "15.3.1",
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
"devDependencies": {
"@types/node": "^22",
"@types/react": "^18.3.0",
"@types/react-dom": "^18.3.0",
"autoprefixer": "^10.4.20",
"eslint": "^9.18.0",
"eslint-config-next": "15.3.1",
"postcss": "^8.4.49",
"tailwindcss": "^3.4.17",
"typescript": "^5.7.3"
}
}

View file

@ -1,177 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Charlotte Croce - Resume">
<title>Resume - Charlotte Croce</title>
<link rel="stylesheet" href="style.css">
<script src="https://unpkg.com/lucide@latest/dist/umd/lucide.min.js"></script>
</head>
<body>
<a href="#main-content" class="skip-link">Skip to main content</a>
<header>
<nav aria-label="Main navigation">
<div class="container">
<a href="/" class="logo">./charlotte.sh</a>
<button class="menu-toggle" aria-expanded="false" aria-controls="primary-menu" aria-label="Toggle menu">
<i data-lucide="menu" id="menu-icon" aria-hidden="true"></i>
<i data-lucide="x" id="close-icon" style="display: none;" aria-hidden="true"></i>
</button>
<ul class="nav-links" id="primary-menu">
<li><a href="https://github.com/charlottecroce" target="_blank" rel="noopener noreferrer">GitHub <i
data-lucide="external-link" class="icon-small" aria-hidden="true"></i><span
class="visually-hidden">(opens in new tab)</span></a></li>
<li><a href="https://git.charlotte.sh" target="_blank" rel="noopener noreferrer">Forgejo <i
data-lucide="external-link" class="icon-small" aria-hidden="true"></i><span
class="visually-hidden">(opens in new tab)</span></a></li>
<li><a href="https://linkedin.com/in/charlottecroce" target="_blank" rel="noopener noreferrer">LinkedIn <i
data-lucide="external-link" class="icon-small" aria-hidden="true"></i><span
class="visually-hidden">(opens in new tab)</span></a></li>
<li>
<button class="theme-toggle" aria-label="Toggle dark mode">
<i data-lucide="moon" id="moon-icon" aria-hidden="true"></i>
<i data-lucide="sun" id="sun-icon" style="display: none;" aria-hidden="true"></i>
</button>
</li>
</ul>
</div>
</nav>
</header>
<main id="main-content">
<div class="container">
<section class="intro">
<div class="resume-header">
<h1>Charlotte Croce</h1>
<div class="contact-info">
</div>
</div>
</section>
<section class="resume-section">
<h2>Education</h2>
<div class="education-item">
<div class="education-header">
<h3>Champlain College</h3>
<span class="location">Burlington, VT</span>
</div>
<div class="education-header">
<div class="degree">Bachelor of Science in Computer Networking and Cybersecurity</div>
<span class="date">Class of 2027</span>
</div>
<div class="gpa">GPA: 3.97/4.0</div>
<div class="coursework">
<strong>Relevant Coursework:</strong> Network Security Controls, Web & Application Security, Database
Security, System Administration for Enterprise and Distributed Systems, Automation & Scripting
</div>
</div>
</section>
<section class="resume-section">
<h2>Experience</h2>
<div class="experience-item">
<div class="experience-header">
<h3>The Leahy Center</h3>
<span class="location">Burlington, VT</span>
</div>
<div class="experience-header">
<div class="job-title">Security Engineer</div>
<span class="date">Jan 2024 — Present</span>
</div>
<ul class="bullet-list">
<li>Maintained SIEM infrastructure, ensured uptime, and automated security operations</li>
<li>Optimized a threat detection engine to expand security coverage while reducing false positives
</li>
<li>Developed an Elastic Stack dev environment for feature testing</li>
<li>Collaborated with analysts on alert response</li>
</ul>
<div class="experience-header">
<div class="job-title">SOC Intern</div>
<span class="date">Oct 2023 — Dec 2023</span>
</div>
</div>
</section>
<section class="resume-section">
<h2>Certifications</h2>
<div class="skills-grid">
<div class="skill-category">CompTIA CySA+</div>
<div class="skill-category">CompTIA Security+</div>
<div class="skill-category">CompTIA A+</div>
</div>
</section>
<section class="resume-section">
<h2>Skills</h2>
<h3 class="skill-heading">Systems & Infrastructure</h3>
<div class="skills-grid">
<div class="skill-category">Active Directory</div>
<div class="skill-category">Debian Linux</div>
<div class="skill-category">Docker</div>
<div class="skill-category">RHEL Linux</div>
<div class="skill-category">VMWare</div>
<div class="skill-category">Windows Server</div>
</div>
<h3 class="skill-heading">Security Tools & Frameworks</h3>
<div class="skills-grid">
<div class="skill-category">Elastic Stack</div>
<div class="skill-category">Firewalls</div>
<div class="skill-category">PKI</div>
<div class="skill-category">SIEM</div>
<div class="skill-category">Wireshark</div>
</div>
<h3 class="skill-heading">Networking</h3>
<div class="skills-grid">
<div class="skill-category">VyOS</div>
</div>
<h3 class="skill-heading">Programming & Scripting</h3>
<div class="skills-grid">
<div class="skill-category">Ansible</div>
<div class="skill-category">Bash</div>
<div class="skill-category">Java</div>
<div class="skill-category">JavaScript</div>
<div class="skill-category">PowerShell</div>
<div class="skill-category">Python</div>
<div class="skill-category">SQL</div>
</div>
<h3 class="skill-heading">Project Management</h3>
<div class="skills-grid">
<div class="skill-category">Git / GitHub</div>
</div>
</section>
</div>
</main>
<footer>
<div class="container">
<ul class="social-links">
<li><a href="https://github.com/charlottecroce" target="_blank" rel="noopener noreferrer">GitHub</a></li>
<li><a href="https://git.charlotte.sh/lotte" target="_blank" rel="noopener noreferrer">Forgejo</a></li>
<li><a href="https://linkedin.com/in/charlottecroce" target="_blank" rel="noopener noreferrer">LinkedIn</a></li>
<li><a href="https://hachyderm.io/@charlotte200" target="_blank" rel="noopener noreferrer me">Mastodon</a></li>
<li><a href="https://bookwyrm.social/user/lottie" target="_blank" rel="noopener noreferrer">BookWyrm</a></li>
<li><a href="https://rss.charlotte.sh" target="_blank" rel="noopener noreferrer"><i data-lucide="rss" class="icon-small" aria-hidden="true"></i><span class="visually-hidden">FreshRSS</span></a></li>
</ul>
<p>&copy;<span id="current-year"></span> Charlotte Croce</p>
<p class="theme-note">If you like the colors of this website, check out my <a
href="https://marketplace.visualstudio.com/items?itemName=charlotte-dev.fruitbasket-theme" target="_blank"
rel="noopener noreferrer">VS Code Theme<i data-lucide="external-link" class="icon-small"
aria-hidden="true"></i><span class="visually-hidden">(opens in new tab)</span></a></p>
</div>
</footer>
<script src="script.js"></script>
</body>
</html>

View file

@ -1,49 +0,0 @@
// Initialize Lucide icons
lucide.createIcons();
// Update copyright year
document.getElementById('current-year').textContent = new Date().getFullYear();
// Theme toggle
const themeToggle = document.querySelector('.theme-toggle');
const moonIcon = document.getElementById('moon-icon');
const sunIcon = document.getElementById('sun-icon');
// Check for saved preference
if (localStorage.getItem('darkMode') === 'true') {
document.body.classList.add('dark-mode');
moonIcon.style.display = 'none';
sunIcon.style.display = 'block';
}
themeToggle.addEventListener('click', () => {
document.body.classList.toggle('dark-mode');
const isDark = document.body.classList.contains('dark-mode');
moonIcon.style.display = isDark ? 'none' : 'block';
sunIcon.style.display = isDark ? 'block' : 'none';
localStorage.setItem('darkMode', isDark ? 'true' : 'false');
});
// Mobile menu
const menuToggle = document.querySelector('.menu-toggle');
const navLinks = document.querySelector('.nav-links');
const menuIcon = document.getElementById('menu-icon');
const closeIcon = document.getElementById('close-icon');
menuToggle.addEventListener('click', () => {
const isExpanded = menuToggle.getAttribute('aria-expanded') === 'true';
menuToggle.setAttribute('aria-expanded', !isExpanded);
navLinks.classList.toggle('menu-open');
menuIcon.style.display = isExpanded ? 'block' : 'none';
closeIcon.style.display = isExpanded ? 'none' : 'block';
});
// Close menu when clicking outside
document.addEventListener('click', (event) => {
if (!event.target.closest('.menu-toggle') && !event.target.closest('.nav-links') && navLinks.classList.contains('menu-open')) {
navLinks.classList.remove('menu-open');
menuToggle.setAttribute('aria-expanded', 'false');
menuIcon.style.display = 'block';
closeIcon.style.display = 'none';
}
});

View file

@ -1,6 +1,4 @@
/* CSS Variables */
:root { :root {
/* Pink palette */
--pink-50: #FFF0F5; --pink-50: #FFF0F5;
--pink-100: #FFE0EB; --pink-100: #FFE0EB;
--pink-200: #FFB8D9; --pink-200: #FFB8D9;
@ -8,24 +6,20 @@
--pink-400: #F45D9E; --pink-400: #F45D9E;
--pink-500: #D23B80; --pink-500: #D23B80;
/* Sage palette */
--sage-200: #D4E6D5; --sage-200: #D4E6D5;
--sage-300: #B5D4B7; --sage-300: #B5D4B7;
--sage-400: #8AB68C; --sage-400: #8AB68C;
--sage-500: #6A9A6C; --sage-500: #6A9A6C;
/* Neutral palette */
--cream-50: #FFFEF5; --cream-50: #FFFEF5;
--cream-100: #FFF9F0; --cream-100: #FFF9F0;
/* Semantic colors */
--text: #4a4a4a; --text: #4a4a4a;
--bg-primary: var(--pink-50); --bg-primary: var(--pink-50);
--bg-secondary: white; --bg-secondary: white;
--accent-primary: var(--pink-400); --accent-primary: var(--pink-400);
--accent-secondary: var(--sage-400); --accent-secondary: var(--sage-400);
/* Spacing */
--space-xs: 0.25rem; --space-xs: 0.25rem;
--space-sm: 0.5rem; --space-sm: 0.5rem;
--space-md: 1rem; --space-md: 1rem;
@ -33,14 +27,10 @@
--space-xl: 2rem; --space-xl: 2rem;
--space-xxl: 3rem; --space-xxl: 3rem;
/* Container */
--container-max: 1200px; --container-max: 1200px;
/* Animation */
--transition: 0.2s ease; --transition: 0.2s ease;
} }
/* Reset */
*, *,
*::before, *::before,
*::after { *::after {
@ -49,7 +39,6 @@
padding: 0; padding: 0;
} }
/* Base styles */
body { body {
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', sans-serif; font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', sans-serif;
line-height: 1.6; line-height: 1.6;
@ -68,7 +57,6 @@ body {
padding: 0 var(--space-md); padding: 0 var(--space-md);
} }
/* Accessibility */
.skip-link { .skip-link {
position: absolute; position: absolute;
top: -40px; top: -40px;
@ -96,7 +84,6 @@ body {
border: 0; border: 0;
} }
/* Typography */
h1, h1,
h2, h2,
h3 { h3 {
@ -135,13 +122,11 @@ a:focus {
text-decoration: underline; text-decoration: underline;
} }
/* Focus styles */
:focus { :focus {
outline: 3px solid var(--pink-300); outline: 3px solid var(--pink-300);
outline-offset: 3px; outline-offset: 3px;
} }
/* Header & Navigation */
header { header {
background-color: var(--bg-primary); background-color: var(--bg-primary);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
@ -239,7 +224,6 @@ nav .container {
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
} }
/* Main content */
main { main {
flex: 1; flex: 1;
padding: var(--space-xxl) 0; padding: var(--space-xxl) 0;
@ -318,7 +302,6 @@ main {
margin-left: var(--space-xs); margin-left: var(--space-xs);
} }
/* Footer */
footer { footer {
background-color: var(--pink-100); background-color: var(--pink-100);
padding: var(--space-xl); padding: var(--space-xl);
@ -345,7 +328,6 @@ footer {
display: inline-block; display: inline-block;
} }
/* Dark mode */
.dark-mode { .dark-mode {
--pink-50: #3A2A35; --pink-50: #3A2A35;
--pink-100: #59354B; --pink-100: #59354B;
@ -365,7 +347,6 @@ footer {
background: linear-gradient(to right, var(--pink-400), transparent); background: linear-gradient(to right, var(--pink-400), transparent);
} }
/* Responsive design */
@media (max-width: 768px) { @media (max-width: 768px) {
.menu-toggle { .menu-toggle {
display: flex; display: flex;
@ -430,10 +411,6 @@ footer {
} }
} }
/* Resume header and contact info */
.resume-header { .resume-header {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -448,7 +425,6 @@ footer {
font-size: 0.95rem; font-size: 0.95rem;
} }
/* Resume sections */
.resume-section { .resume-section {
background-color: var(--bg-secondary); background-color: var(--bg-secondary);
border-radius: 0.75rem; border-radius: 0.75rem;
@ -481,7 +457,6 @@ footer {
background: linear-gradient(to right, var(--pink-400), transparent); background: linear-gradient(to right, var(--pink-400), transparent);
} }
/* Education and experience items */
.education-item, .education-item,
.experience-item { .experience-item {
margin-bottom: var(--space-lg); margin-bottom: var(--space-lg);
@ -528,7 +503,6 @@ footer {
margin-bottom: var(--space-xs); margin-bottom: var(--space-xs);
} }
/* Skills grid */
.skills-grid { .skills-grid {
display: grid; display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
@ -547,7 +521,6 @@ footer {
font-size: 1.5rem; font-size: 1.5rem;
} }
/* Print styles */
@media print { @media print {
body { body {
background-color: white; background-color: white;
@ -577,7 +550,6 @@ footer {
} }
} }
/* Skill category headings */
.skill-heading { .skill-heading {
font-size: 1.1rem; font-size: 1.1rem;
color: var(--accent-primary); color: var(--accent-primary);
@ -587,19 +559,15 @@ footer {
padding-bottom: var(--space-xs); padding-bottom: var(--space-xs);
} }
/* Make the first skill heading not have extra top margin */
.skill-heading:first-of-type { .skill-heading:first-of-type {
margin-top: 0; margin-top: 0;
} }
/* Dark mode styling for skill headings */
.dark-mode .skill-heading { .dark-mode .skill-heading {
border-bottom-color: var(--pink-300); border-bottom-color: var(--pink-300);
} }
/* Responsive adjustments for resume */
@media (max-width: 768px) { @media (max-width: 768px) {
.education-header, .education-header,
.experience-header { .experience-header {
flex-direction: column; flex-direction: column;
@ -612,4 +580,78 @@ footer {
.skills-grid { .skills-grid {
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
} }
}
/* Workout Filters */
.filters-container {
display: flex;
gap: var(--space-xl);
margin-bottom: var(--space-xl);
flex-wrap: wrap;
}
.filter-group {
display: flex;
align-items: center;
gap: var(--space-sm);
}
.filter-group label {
font-weight: 500;
color: var(--accent-secondary);
}
.filter-select {
padding: var(--space-sm) var(--space-md);
border-radius: 9999px;
border: 1px solid var(--sage-200);
background-color: var(--bg-secondary);
color: var(--text);
font-size: 0.95rem;
cursor: pointer;
transition: all var(--transition);
}
.filter-select:hover,
.filter-select:focus {
border-color: var(--pink-300);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}
.dark-mode .filter-select {
border-color: var(--pink-300);
}
.dark-mode .filter-select:hover,
.dark-mode .filter-select:focus {
border-color: var(--pink-400);
}
@media (max-width: 768px) {
.filters-container {
flex-direction: column;
gap: var(--space-md);
}
.filter-group {
width: 100%;
}
.filter-select {
flex: 1;
}
}
/* Workout Details */
.back-link {
display: inline-flex;
align-items: center;
gap: var(--space-xs);
margin-bottom: var(--space-xl);
color: var(--accent-primary);
transition: all var(--transition);
}
.back-link:hover {
transform: translateX(-4px);
} }

26
src/app/layout.tsx Normal file
View file

@ -0,0 +1,26 @@
'use client';
import { usePathname } from 'next/navigation';
import { Header } from '@/components/Header/Header';
import { Footer } from '@/components/Footer/Footer';
import './globals.css';
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
const pathname = usePathname();
const isWorkoutPage = pathname?.startsWith('/workouts');
return (
<html lang="en">
<body>
<a href="#main-content" className="skip-link">Skip to main content</a>
<Header />
<main id="main-content">{children}</main>
{!isWorkoutPage && <Footer />}
</body>
</html>
);
}

26
src/app/page.tsx Normal file
View file

@ -0,0 +1,26 @@
import Link from 'next/link';
import { ProjectCard } from '@/components/ProjectCard/ProjectCard';
import { projects } from '@/data/projects';
export default function Home() {
return (
<div className="container">
<section className="intro">
<h1>Hi! I'm Charlotte</h1>
<h2>About Me</h2>
<p>I&apos;m a cybersecurity student from the Northeast USA. I currently work as a security engineer at the Leahy Center in Burlington, VT.</p>
<p>Most of my coding projects are hosted on my Forgejo server at <a href="https://git.charlotte.sh/" target="_blank" rel="noopener noreferrer">git.charlotte.sh</a></p>
<p>Hiring? you can find my resume <Link href="/resume">here</Link></p>
</section>
<section className="projects">
<h2>My Projects</h2>
<div className="project-grid">
{projects.map((project) => (
<ProjectCard key={project.id} project={project} />
))}
</div>
</section>
</div>
);
}

0
src/app/providers.tsx Normal file
View file

77
src/app/resume/page.tsx Normal file
View file

@ -0,0 +1,77 @@
import type { Metadata } from 'next';
import { SkillGrid } from '@/components/Skills/SkillGrid';
import { skills } from '@/data/skills';
export const metadata: Metadata = {
title: 'Resume - Charlotte Croce',
description: 'Charlotte Croce - Resume',
};
export default function Resume() {
return (
<div className="container">
<section className="intro">
<div className="resume-header">
<h1>Charlotte Croce</h1>
<div className="contact-info"></div>
</div>
</section>
<section className="resume-section">
<h2>Education</h2>
<div className="education-item">
<div className="education-header">
<h3>Champlain College</h3>
<span className="location">Burlington, VT</span>
</div>
<div className="education-header">
<div className="degree">Bachelor of Science in Computer Networking and Cybersecurity</div>
<span className="date">Class of 2027</span>
</div>
<div className="gpa">GPA: 3.97/4.0</div>
<div className="coursework">
<strong>Relevant Coursework:</strong> Network Security Controls, Web & Application Security, Database Security, System Administration for Enterprise and Distributed Systems, Automation & Scripting
</div>
</div>
</section>
<section className="resume-section">
<h2>Experience</h2>
<div className="experience-item">
<div className="experience-header">
<h3>The Leahy Center</h3>
<span className="location">Burlington, VT</span>
</div>
<div className="experience-header">
<div className="job-title">Security Engineer</div>
<span className="date">Jan 2024 Present</span>
</div>
<ul className="bullet-list">
<li>Maintained SIEM infrastructure, ensured uptime, and automated security operations</li>
<li>Optimized a threat detection engine to expand security coverage while reducing false positives</li>
<li>Developed an Elastic Stack dev environment for feature testing</li>
<li>Collaborated with analysts on alert response</li>
</ul>
<div className="experience-header">
<div className="job-title">SOC Intern</div>
<span className="date">Oct 2023 Dec 2023</span>
</div>
</div>
</section>
<section className="resume-section">
<h2>Certifications</h2>
<div className="skills-grid">
<div className="skill-category">CompTIA CySA+</div>
<div className="skill-category">CompTIA Security+</div>
<div className="skill-category">CompTIA A+</div>
</div>
</section>
<section className="resume-section">
<h2>Skills</h2>
<SkillGrid skills={skills} showHeadings={true} />
</section>
</div>
);
}

View file

@ -0,0 +1,71 @@
import { notFound } from 'next/navigation';
import Link from 'next/link';
import { Clock, Dumbbell, ArrowLeft } from 'lucide-react';
import { workouts } from '@/data/workouts';
export function generateStaticParams() {
return workouts.map((workout) => ({
id: workout.id,
}));
}
export default function WorkoutPage({ params }: { params: { id: string } }) {
const workout = workouts.find(w => w.id === params.id);
if (!workout) {
notFound();
}
const difficultyColors = {
recovery: 'var(--sage-300)',
easy: 'var(--sage-400)',
moderate: 'var(--pink-300)',
strenuous: 'var(--pink-400)'
};
return (
<div className="container">
<Link href="/workouts" className="back-link">
<ArrowLeft size={16} />
Back to all workouts
</Link>
<section className="intro">
<h1>{workout.title}</h1>
{workout.description && <p>{workout.description}</p>}
<div style={{ display: 'flex', gap: 'var(--space-xl)', marginTop: 'var(--space-md)' }}>
<span style={{
display: 'inline-flex',
alignItems: 'center',
gap: 'var(--space-xs)',
color: difficultyColors[workout.difficulty],
fontWeight: 500
}}>
<Dumbbell size={20} />
{workout.difficulty.charAt(0).toUpperCase() + workout.difficulty.slice(1)}
</span>
<span style={{
display: 'inline-flex',
alignItems: 'center',
gap: 'var(--space-xs)',
fontWeight: 500
}}>
<Clock size={20} />
{workout.duration} minutes
</span>
</div>
</section>
<section className="resume-section">
<h2>Exercises</h2>
<ul className="bullet-list">
{workout.exercises.map((exercise, index) => (
<li key={index}>{exercise}</li>
))}
</ul>
</section>
</div>
);
}

55
src/app/workouts/page.tsx Normal file
View file

@ -0,0 +1,55 @@
'use client';
import { useState } from 'react';
import type { Metadata } from 'next';
import { WorkoutCard } from '@/components/WorkoutCard/WorkoutCard';
import { WorkoutFilters } from '@/components/WorkoutFilters/WorkoutFilters';
import { workouts } from '@/data/workouts';
import { WorkoutDifficulty, WorkoutDuration } from '@/types';
export default function WorkoutsPage() {
const [selectedDifficulty, setSelectedDifficulty] = useState<WorkoutDifficulty | null>(null);
const [selectedDuration, setSelectedDuration] = useState<WorkoutDuration | null>(null);
const filteredWorkouts = workouts.filter(workout => {
if (selectedDifficulty && workout.difficulty !== selectedDifficulty) {
return false;
}
if (selectedDuration && workout.duration !== selectedDuration) {
return false;
}
return true;
});
return (
<div className="container">
<section className="intro">
<h1>Uphill Fitness</h1>
<p>A collection of workouts I use to improve my mountaineering fitness</p>
</section>
<section className="projects">
<h2>Workouts</h2>
<WorkoutFilters
selectedDifficulty={selectedDifficulty}
selectedDuration={selectedDuration}
onDifficultyChange={setSelectedDifficulty}
onDurationChange={setSelectedDuration}
/>
<div className="project-grid">
{filteredWorkouts.map((workout) => (
<WorkoutCard key={workout.id} workout={workout} />
))}
</div>
{filteredWorkouts.length === 0 && (
<p style={{ textAlign: 'center', color: 'var(--accent-secondary)', marginTop: 'var(--space-xl)' }}>
No workouts found matching your criteria. Try adjusting your filters.
</p>
)}
</section>
</div>
);
}

View file

@ -0,0 +1,42 @@
import { ExternalLink, Rss } from 'lucide-react';
import { footerLinks } from '@/data/social';
export function Footer() {
const currentYear = new Date().getFullYear();
return (
<footer>
<div className="container">
<ul className="social-links">
{footerLinks.map((link) => (
<li key={link.name}>
<a href={link.url} target="_blank" rel="noopener noreferrer">
{link.icon === 'rss' ? (
<>
<Rss className="icon-small" aria-hidden="true" />
<span className="visually-hidden">FreshRSS</span>
</>
) : (
link.name
)}
</a>
</li>
))}
</ul>
<p>&copy;{currentYear} Charlotte Croce</p>
<p className="theme-note">
If you like the colors of this website, check out my{' '}
<a
href="https://marketplace.visualstudio.com/items?itemName=charlotte-dev.fruitbasket-theme"
target="_blank"
rel="noopener noreferrer"
>
VS Code Theme
<ExternalLink className="icon-small" aria-hidden="true" />
<span className="visually-hidden">(opens in new tab)</span>
</a>
</p>
</div>
</footer>
);
}

View file

@ -0,0 +1,9 @@
import { Navigation } from './Navigation';
export function Header() {
return (
<header>
<Navigation />
</header>
);
}

View file

@ -0,0 +1,55 @@
'use client';
import { useState, useEffect } from 'react';
import Link from 'next/link';
import { Menu, X, ExternalLink } from 'lucide-react';
import { ThemeToggle } from './ThemeToggle';
import { headerLinks } from '@/data/social';
export function Navigation() {
const [isMenuOpen, setIsMenuOpen] = useState(false);
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
const target = event.target as HTMLElement;
if (!target.closest('.menu-toggle') && !target.closest('.nav-links') && isMenuOpen) {
setIsMenuOpen(false);
}
};
document.addEventListener('click', handleClickOutside);
return () => document.removeEventListener('click', handleClickOutside);
}, [isMenuOpen]);
return (
<nav aria-label="Main navigation">
<div className="container">
<Link href="/" className="logo">./charlotte.sh</Link>
<button
className="menu-toggle"
aria-expanded={isMenuOpen}
aria-controls="primary-menu"
aria-label="Toggle menu"
onClick={() => setIsMenuOpen(!isMenuOpen)}
>
{isMenuOpen ? <X size={24} /> : <Menu size={24} />}
</button>
<ul className={`nav-links ${isMenuOpen ? 'menu-open' : ''}`} id="primary-menu">
{headerLinks.map((link) => (
<li key={link.name}>
<a href={link.url} target="_blank" rel="noopener noreferrer">
{link.name} <ExternalLink className="icon-small" />
<span className="visually-hidden">(opens in new tab)</span>
</a>
</li>
))}
<li>
<ThemeToggle />
</li>
</ul>
</div>
</nav>
);
}

View file

@ -0,0 +1,20 @@
'use client';
import { Moon, Sun } from 'lucide-react';
import { useTheme } from '@/hooks/useTheme';
export function ThemeToggle() {
const { isDarkMode, toggleTheme, mounted } = useTheme();
if (!mounted) return <div className="w-9 h-9" />;
return (
<button
onClick={toggleTheme}
className="theme-toggle"
aria-label="Toggle dark mode"
>
{isDarkMode ? <Sun size={18} /> : <Moon size={18} />}
</button>
);
}

View file

@ -0,0 +1,12 @@
'use client';
import { useEffect } from 'react';
import * as lucideIcons from 'lucide-react';
export function IconWrapper({ name, className = '', ...props }: { name: string; className?: string; [key: string]: any }) {
const Icon = lucideIcons[name as keyof typeof lucideIcons] as any;
if (!Icon) return null;
return <Icon className={className} {...props} />;
}

View file

@ -0,0 +1,16 @@
import { ExternalLink } from 'lucide-react';
import { Project } from '@/types';
export function ProjectCard({ project }: { project: Project }) {
return (
<article className="project">
<h3>{project.title}</h3>
<p>{project.description}</p>
<a href={project.sourceUrl} target="_blank" rel="noopener noreferrer">
Source Code
<ExternalLink className="icon-small" aria-hidden="true" />
<span className="visually-hidden">(opens in new tab)</span>
</a>
</article>
);
}

View file

@ -0,0 +1,34 @@
import { Skill } from '@/types';
export function SkillGrid({ skills, showHeadings = false }: { skills: Skill[]; showHeadings?: boolean }) {
if (showHeadings) {
return (
<>
{skills.map((skillCategory, index) => (
<div key={skillCategory.category}>
<h3 className={`skill-heading ${index === 0 ? 'mt-0' : ''}`}>{skillCategory.category}</h3>
<div className="skills-grid">
{skillCategory.items.map((skill) => (
<div key={skill} className="skill-category">
{skill}
</div>
))}
</div>
</div>
))}
</>
);
}
return (
<div className="skills-grid">
{skills.map((skillCategory) =>
skillCategory.items.map((skill) => (
<div key={skill} className="skill-category">
{skill}
</div>
))
)}
</div>
);
}

View file

@ -0,0 +1,39 @@
import Link from 'next/link';
import { Clock, Dumbbell } from 'lucide-react';
import { Workout } from '@/types';
export function WorkoutCard({ workout }: { workout: Workout }) {
const difficultyColors = {
recovery: 'var(--sage-300)',
easy: 'var(--sage-400)',
moderate: 'var(--pink-300)',
strenuous: 'var(--pink-400)'
};
return (
<article className="project">
<h3>{workout.title}</h3>
{workout.description && <p>{workout.description}</p>}
<div style={{ display: 'flex', gap: 'var(--space-md)', margin: 'var(--space-sm) 0' }}>
<span style={{
display: 'inline-flex',
alignItems: 'center',
gap: 'var(--space-xs)',
color: difficultyColors[workout.difficulty]
}}>
<Dumbbell size={16} />
{workout.difficulty}
</span>
<span style={{ display: 'inline-flex', alignItems: 'center', gap: 'var(--space-xs)' }}>
<Clock size={16} />
{workout.duration} mins
</span>
</div>
<Link href={`/workouts/${workout.id}`} style={{ display: 'inline-flex', alignItems: 'center' }}>
View Workout
</Link>
</article>
);
}

View file

@ -0,0 +1,58 @@
'use client';
import { WorkoutDifficulty, WorkoutDuration } from '@/types';
interface WorkoutFiltersProps {
selectedDifficulty: WorkoutDifficulty | null;
selectedDuration: WorkoutDuration | null;
onDifficultyChange: (difficulty: WorkoutDifficulty | null) => void;
onDurationChange: (duration: WorkoutDuration | null) => void;
}
export function WorkoutFilters({
selectedDifficulty,
selectedDuration,
onDifficultyChange,
onDurationChange
}: WorkoutFiltersProps) {
const difficulties: WorkoutDifficulty[] = ['recovery', 'easy', 'moderate', 'strenuous'];
const durations: WorkoutDuration[] = [30, 60, 90, 120, 150, 180, 210, 240, 270, 300];
return (
<div className="filters-container">
<div className="filter-group">
<label htmlFor="difficulty-filter">Difficulty:</label>
<select
id="difficulty-filter"
value={selectedDifficulty || ''}
onChange={(e) => onDifficultyChange(e.target.value ? e.target.value as WorkoutDifficulty : null)}
className="filter-select"
>
<option value="">All difficulties</option>
{difficulties.map(diff => (
<option key={diff} value={diff}>
{diff.charAt(0).toUpperCase() + diff.slice(1)}
</option>
))}
</select>
</div>
<div className="filter-group">
<label htmlFor="duration-filter">Duration:</label>
<select
id="duration-filter"
value={selectedDuration || ''}
onChange={(e) => onDurationChange(e.target.value ? Number(e.target.value) as WorkoutDuration : null)}
className="filter-select"
>
<option value="">All durations</option>
{durations.map(duration => (
<option key={duration} value={duration}>
{duration} minutes
</option>
))}
</select>
</div>
</div>
);
}

22
src/data/projects.ts Normal file
View file

@ -0,0 +1,22 @@
import { Project } from '@/types';
export const projects: Project[] = [
{
id: 'fylgja-soc',
title: 'Fylgja SOC',
description: 'A domain-specific language (DSL) for managing an ELK SIEM. Includes a CLI and SlackBot interface [WIP]',
sourceUrl: 'https://git.charlotte.sh/lotte/fylgja'
},
{
id: 'champlain-tech-journals',
title: 'Champlain Tech Journals',
description: 'Notes, code, and lab write-ups from my Champlain College courses',
sourceUrl: 'https://git.charlotte.sh/lotte/ChamplainTechJournals'
},
{
id: 'nokken-health',
title: 'Nøkken Health',
description: 'A Flutter app to track and analyze health data [MVP]',
sourceUrl: 'https://git.charlotte.sh/lotte/nokken'
}
];

24
src/data/skills.ts Normal file
View file

@ -0,0 +1,24 @@
import { Skill } from '@/types';
export const skills: Skill[] = [
{
category: 'Systems & Infrastructure',
items: ['Active Directory', 'Debian Linux', 'Docker', 'RHEL Linux', 'VMWare', 'Windows Server']
},
{
category: 'Security Tools & Frameworks',
items: ['Elastic Stack', 'Firewalls', 'PKI', 'SIEM', 'Wireshark']
},
{
category: 'Networking',
items: ['VyOS']
},
{
category: 'Programming & Scripting',
items: ['Ansible', 'Bash', 'Java', 'JavaScript', 'PowerShell', 'Python', 'SQL']
},
{
category: 'Project Management',
items: ['Git / GitHub']
}
];

16
src/data/social.ts Normal file
View file

@ -0,0 +1,16 @@
import { SocialLink } from '@/types';
export const headerLinks: SocialLink[] = [
{ name: 'GitHub', url: 'https://github.com/charlottecroce' },
{ name: 'Forgejo', url: 'https://git.charlotte.sh' },
{ name: 'LinkedIn', url: 'https://linkedin.com/in/charlottecroce' }
];
export const footerLinks: SocialLink[] = [
{ name: 'GitHub', url: 'https://github.com/charlottecroce' },
{ name: 'Forgejo', url: 'https://git.charlotte.sh/lotte' },
{ name: 'LinkedIn', url: 'https://linkedin.com/in/charlottecroce' },
{ name: 'Mastodon', url: 'https://hachyderm.io/@charlotte200' },
{ name: 'BookWyrm', url: 'https://bookwyrm.social/user/lottie' },
{ name: 'FreshRSS', url: 'https://rss.charlotte.sh', icon: 'rss' }
];

992
src/data/workouts.ts Normal file
View file

@ -0,0 +1,992 @@
import { Workout } from '@/types';
export const workouts: Workout[] = [
// STRENGTH TRAINING WORKOUTS
{
id: 'alpine-strength-upper',
title: 'Alpine Upper Body Power',
difficulty: 'strenuous',
duration: 90,
description: 'Upper body strength training for pulling movements crucial in mountaineering',
exercises: [
'Shoulder circles: 20 forward, 20 backward each arm',
'Arm swings: 20 cross-body swings per arm',
'Scapular push-ups: 2 sets of 15 reps',
'Band pull-aparts: 2 sets of 20 reps',
'Weighted pull-ups: 5 sets of 6-8 reps (add weight via belt)',
'Lat pulldowns with pause at bottom: 4 sets of 12 reps (3-second hold)',
'Rope pulls (seated, hand over hand): 4 sets of 30 seconds',
'Single-arm dumbbell rows: 4 sets of 10 reps per arm (2-second pause at top)',
'TRX body rows (feet elevated): 3 sets of 15 reps',
'Alternating dumbbell curls (simulate ice axe): 4 sets of 12 reps',
'Face pulls with external rotation: 3 sets of 15 reps',
'Wall angels: 3 sets of 15 reps',
'Dead hangs from pull-up bar: 3 sets of 60 seconds',
'Doorway chest stretch: 30 seconds each side',
'Cross-body shoulder stretch: 30 seconds each arm',
'Overhead triceps stretch: 30 seconds each arm'
]
},
{
id: 'alpine-strength-lower',
title: 'Alpine Lower Body Strength',
difficulty: 'strenuous',
duration: 120,
description: 'Leg strength workout for steep ascents and heavy load carrying',
exercises: [
'Forward leg swings: 15 each leg',
'Lateral leg swings: 15 each leg',
'Walking knee hugs: 10 each leg',
'Walking quad stretch: 10 each leg',
'Ankle circles: 20 each direction per ankle',
'Front squats (barbell): 5 sets of 8 reps',
'Single-leg Romanian deadlifts: 4 sets of 10 reps per leg',
'Weighted box step-ups (24" box, dumbbells): 4 sets of 15 reps per leg',
'Walking lunges with 60lb backpack: 4 sets of 20 total steps',
'Bulgarian split squats (rear foot elevated): 3 sets of 12 reps per leg',
'Single-leg calf raises on step: 4 sets of 30 reps per leg',
'Seated calf raises with weight: 3 sets of 20 reps',
'Tibialis raises (toes against wall): 3 sets of 20 reps',
'Standing quad stretch: 60 seconds each leg',
'Pigeon pose: 90 seconds each side',
'Seated forward fold: 2 minutes',
'Butterfly stretch: 90 seconds'
]
},
{
id: 'core-stability-alpine',
title: 'Alpine Core Stability',
difficulty: 'moderate',
duration: 60,
description: 'Core workout focused on stability for uneven terrain and load carrying',
exercises: [
'Cat-cow: 10 repetitions',
'Bird dogs: 10 reps each side (hold 5 seconds each)',
'Dead bugs with band: 3 sets of 20 reps (opposite arm/leg)',
'Pallof press (cable or band): 4 sets of 15 reps each side',
'Weighted plank (plate on back): 4 sets of 60 seconds',
'Side plank with top leg raised: 3 sets of 30 seconds each side',
'Side plank thread the needle: 3 sets of 12 reps each side',
'McGill curl-ups: 4 sets of 20 reps (hold 8 seconds each)',
'Farmer\'s carry with kettlebells: 4 sets of 60 seconds',
'Single-arm farmer\'s carry: 3 sets of 30 seconds each side',
'Turkish get-ups: 3 sets of 5 reps each side',
'Child\'s pose: 60 seconds',
'Cobra stretch: 30 seconds',
'Seated spinal twist: 60 seconds each side'
]
},
// CARDIOVASCULAR ENDURANCE WORKOUTS
{
id: 'altitude-simulator-intervals',
title: 'Altitude Simulation Intervals',
difficulty: 'strenuous',
duration: 90,
description: 'High-intensity intervals to prepare for reduced oxygen at altitude',
exercises: [
'Easy jog: 5 minutes',
'Dynamic stretching: high knees, butt kicks, leg swings (5 minutes)',
'Gradual incline walk: start flat, increase to 10% over 5 minutes',
'Stairmaster intervals: 2 minutes at level 12-14, 1 minute at level 6',
'Repeat stairmaster interval 8 times',
'Treadmill at 15% grade: 3 minutes at 3.5mph, 2 minutes at 2.5mph',
'Repeat treadmill interval 5 times',
'Box step-ups with 20lb vest: 50 continuous reps, right leg leads',
'Rest 90 seconds',
'Box step-ups with 20lb vest: 50 continuous reps, left leg leads',
'Rest 90 seconds',
'Repeat box step-ups 2 more times each leg',
'Cool down walk at 0% incline: 5 minutes',
'Box breathing: 4 seconds in, 4 hold, 4 out, 4 hold (5 minutes)'
]
},
{
id: 'long-endurance-hike',
title: 'Long Day Simulation',
difficulty: 'strenuous',
duration: 260,
description: 'Extended endurance workout simulating a long climbing day',
exercises: [
'Pack adjustment and gear check: ensure proper weight distribution (5 minutes)',
'Dynamic warm-up: arm circles, leg swings, torso twists (10 minutes)',
'Treadmill hiking at 15% incline, 2.5mph with 60lb pack: 30 minutes',
'Treadmill hiking at 12% incline, 3.0mph with 60lb pack: 30 minutes',
'Treadmill hiking at 18% incline, 2.0mph with 60lb pack: 30 minutes',
'Stairmaster with 60lb pack, level 8: 15 minutes',
'Stairmaster with 60lb pack, level 10: 15 minutes',
'Stairmaster with 60lb pack, level 6: 15 minutes',
'Practice eating/drinking while walking: consume 200 calories (15 minutes)',
'Treadmill varied incline: 5 minutes each at 5%, 10%, 15%, 10%, 5% (30 minutes)',
'Treadmill steady pace: 10% incline at 2.8mph for 35 minutes',
'Step-ups on 18" box: 3 sets of 30 per leg (15 minutes)',
'Walking lunges: 3 sets of 30 steps (15 minutes)',
'Standing quad stretch: 60 seconds each leg',
'Hamstring stretch on bench: 60 seconds each leg',
'Calf stretch against wall: 60 seconds each side',
'Hip flexor stretch: 90 seconds each side',
'Spinal twists: 60 seconds each side'
]
},
{
id: 'zone-2-endurance',
title: 'Zone 2 Base Building',
difficulty: 'moderate',
duration: 120,
description: 'Low-intensity endurance building for aerobic base',
exercises: [
'Light arm circles: 20 forward, 20 backward',
'Leg swings: 15 each direction per leg',
'Easy walking: 5 minutes gradually increasing pace',
'Incline treadmill at 10%, maintain heart rate 120-160 bpm: 60 minutes',
'Stairmaster at conversational pace (can speak full sentences): 30 minutes',
'Rowing machine at steady pace, 22-24 strokes per minute: 20 minutes',
'Flat treadmill walk: 5 minutes decreasing pace',
'Standing forward fold: 60 seconds',
'Seated hamstring stretch: 60 seconds each leg',
'Figure-4 hip stretch: 60 seconds each side'
]
},
// WEIGHTED PACK TRAINING
{
id: 'heavy-pack-progression',
title: 'Heavy Pack Progression',
difficulty: 'strenuous',
duration: 150,
description: 'Progressive pack weight training for expedition preparation',
exercises: [
'Unweighted shoulder rolls: 20 forward, 20 backward',
'Hip circles: 15 each direction',
'Bodyweight squats: 20 reps',
'Walking lunges: 20 total steps',
'Stair climbing with 30lb pack: steady pace for 30 minutes',
'Switch to 60lb pack: Treadmill at 10% grade, 2.5mph for 15 minutes',
'Maintain 60lb pack: Treadmill at 10% grade, 3.0mph for 15 minutes',
'Switch to 50lb pack: Box step-ups (18" box), 20 reps right leg',
'Maintain 50lb pack: Box step-ups (18" box), 20 reps left leg',
'Rest 2 minutes, repeat box step-ups',
'Maintain 50lb pack: Walking lunges, 10 steps forward, 10 steps backward',
'Rest 2 minutes, repeat lunges 2 more times',
'Switch to 30lb pack: Stairmaster intervals - 2 min fast, 1 min slow x 7 rounds',
'Remove pack: Hang from pull-up bar 30 seconds',
'Cat-cow pose: 15 repetitions',
'Child\'s pose with side reach: 60 seconds each side',
'Supine spinal twist: 90 seconds each side'
]
},
{
id: 'pack-carry-endurance',
title: 'Pack Carry Endurance',
difficulty: 'moderate',
duration: 180,
description: 'Extended pack carrying for load tolerance',
exercises: [
'Arm swings: 20 each direction',
'Leg swings: 15 each direction per leg',
'Torso rotations: 20 each direction',
'Ankle rolls: 15 each direction per ankle',
'With 35lb pack: Flat treadmill walk at 3.0mph for 30 minutes',
'With 35lb pack: Incline treadmill 5% grade at 2.8mph for 20 minutes',
'With 35lb pack: Incline treadmill 10% grade at 2.5mph for 20 minutes',
'With 35lb pack: Incline treadmill 15% grade at 2.0mph for 20 minutes',
'With 35lb pack: Stairmaster level 6 for 10 minutes',
'With 35lb pack: Stairmaster level 8 for 10 minutes',
'With 35lb pack: Stairmaster level 7 for 10 minutes',
'With 35lb pack: Balance beam walking (or line on floor) for 5 minutes',
'With 35lb pack: Step over 12" hurdles, 20 total',
'With 35lb pack: Duck under 4-foot bar, 20 total',
'With 35lb pack: Lateral steps over 6" barrier, 30 total',
'Remove pack gradually: Walk 5 min with 30lb, 5 min with 15lb, 5 min unweighted',
'Standing side bend: 30 seconds each side',
'Doorway chest stretch: 60 seconds',
'Neck rolls: 10 each direction'
]
},
// TECHNICAL SKILLS TRAINING
{
id: 'balance-proprioception',
title: 'Balance & Proprioception',
difficulty: 'moderate',
duration: 60,
description: 'Balance training for technical terrain and glacier travel',
exercises: [
'Ankle circles: 20 each direction per ankle',
'Single-leg toe touches: 10 per leg',
'Hip circles: 15 each direction',
'Single-leg stand on foam pad: 60 seconds right leg',
'Single-leg stand on foam pad: 60 seconds left leg',
'Repeat foam pad stands 3 more times',
'Bosu ball squats (flat side up): 15 reps',
'Bosu ball squats (round side up): 15 reps',
'Repeat Bosu squats 2 more sets',
'Slackline walking: 5 attempts of maximum distance',
'Slackline standing: Hold for maximum time, 5 attempts',
'Slackline squats: 5 attempts of maximum reps',
'Eyes-closed single-leg stand: 30 seconds right leg',
'Eyes-closed single-leg stand: 30 seconds left leg',
'Repeat eyes-closed stands 2 more times',
'Lateral hops over line: 20 reps each leg',
'Forward/backward hops over line: 20 reps each leg',
'Box jumps with soft landing: 3 sets of 10 reps',
'Agility ladder: High knees pattern for 3 passes',
'Agility ladder: In-in-out-out pattern for 3 passes',
'Agility ladder: Lateral shuffle pattern for 3 passes',
'Ankle alphabet: Write A-Z with each foot',
'Calf stretch on step: 60 seconds each side',
'Ankle dorsiflexion stretch: 60 seconds each side'
]
},
{
id: 'crampon-simulation',
title: 'Crampon Movement Patterns',
difficulty: 'moderate',
duration: 90,
description: 'Movement patterns simulating crampon use on steep terrain',
exercises: [
'Ankle rolls: 20 each direction per ankle',
'Knee circles: 15 each direction per leg',
'Hip flexor march: 20 steps in place',
'Monster walks with band: 20 steps each direction',
'High-knee step-ups (focus on foot flat placement): 20 reps right leg',
'High-knee step-ups: 20 reps left leg',
'Repeat step-ups 3 more sets',
'Lateral step-ups with crossover step: 15 reps leading with right',
'Lateral step-ups with crossover step: 15 reps leading with left',
'Repeat lateral step-ups 2 more sets',
'French technique on stairs: Walk sideways up stairs, 10 flights',
'French technique on stairs: Walk sideways down stairs, 10 flights',
'Front-pointing simulation: High knees against wall, 30 seconds',
'Rest 30 seconds, repeat 2 more times',
'Duck walk on 15% incline treadmill: 2 minutes at 1.5mph',
'Rest 1 minute, repeat 3 more times',
'Backward downhill walking on treadmill (-5% grade): 3 sets of 3 minutes',
'Controlled step-downs from 12" box: 3 sets of 15 per leg',
'Standing calf stretch: 60 seconds each side',
'Seated shin stretch: 60 seconds',
'Kneeling hip flexor stretch: 60 seconds each side'
]
},
// RECOVERY AND FLEXIBILITY
{
id: 'active-recovery-yoga',
title: 'Mountaineer\'s Recovery Yoga',
difficulty: 'recovery',
duration: 60,
description: 'Yoga sequence for mountaineering recovery and flexibility',
exercises: [
'Seated meditation: Focus on breath for 3 minutes',
'Ujjayi breathing: 2 minutes of ocean breath',
'Gentle neck rolls: 5 each direction',
'Sun salutation A: 3 rounds at slow pace',
'Sun salutation B: 2 rounds at slow pace',
'Low lunge with twist: Hold 60 seconds each side',
'Lizard pose: Hold 90 seconds each side',
'Pigeon pose: Hold 2 minutes each side',
'Seated forward fold: Hold 90 seconds',
'Wide-legged forward fold: Hold 90 seconds',
'Pyramid pose: Hold 60 seconds each side',
'Revolved triangle: Hold 60 seconds each side',
'Thread the needle: Hold 60 seconds each side',
'Puppy pose: Hold 90 seconds',
'Seated spinal twist: Hold 60 seconds each side',
'Reclined spinal twist: Hold 90 seconds each side',
'Happy baby pose: Hold 60 seconds',
'Legs up the wall: Hold 5 minutes',
'Savasana: Rest for 5 minutes'
]
},
{
id: 'foam-rolling-recovery',
title: 'Deep Tissue Recovery',
difficulty: 'recovery',
duration: 60,
description: 'Foam rolling and self-myofascial release for recovery',
exercises: [
'Light walking in place: 2 minutes',
'Arm circles: 20 each direction',
'Leg swings: 15 each direction per leg',
'IT band rolling: Start at hip, roll to knee, 90 seconds per side',
'IT band cross-friction: Find tender spots, hold 30 seconds each',
'Quadriceps rolling: Full length of thigh, 90 seconds per side',
'Vastus medialis focus: Inner quad above knee, 60 seconds per side',
'Calf rolling: Full length, 90 seconds per side',
'Peroneal rolling: Outside of shin, 60 seconds per side',
'Tibialis anterior rolling: Front of shin, 60 seconds per side',
'Glute rolling: Figure-4 position, 90 seconds per side',
'Piriformis trigger point: Tennis ball, hold tender spots 30 seconds',
'Upper back rolling: Focus on rhomboids, 2 minutes total',
'Lat rolling: Side-lying position, 60 seconds per side',
'Standing quad stretch: 60 seconds each leg',
'Standing hamstring stretch: 60 seconds each leg',
'Standing calf stretch: 60 seconds each leg'
]
},
// HIGH-INTENSITY TRAINING
{
id: 'summit-day-simulator',
title: 'Summit Day Simulation',
difficulty: 'strenuous',
duration: 300,
description: 'Intense workout simulating summit day conditions and demands',
exercises: [
'Headlamp warm-up: All exercises done with reduced lighting',
'Dynamic stretches with headlamp: Leg swings, arm circles (5 minutes)',
'Layer management practice: Add/remove layers while moving (5 minutes)',
'Joint mobility in cold simulation: Slow, controlled movements (5 minutes)',
'Heavy pack (60lb) stair climbing: Steady pace for 20 minutes',
'Maintain pace for 20 minutes',
'Increase pace slightly for final 20 minutes',
'HIIT with 60lb pack: 30 seconds sprint stairs, 30 seconds rest x 15',
'HIIT with 60lb pack: 60 seconds fast step-ups, 15 seconds rest x 15',
'HIIT with 60lb pack: 60 seconds incline treadmill run, 60 seconds walk x 8',
'Balance beam with pack: Walk forward, backward, sideways (10 minutes)',
'High step practice: Step over 24" barriers x 30',
'Rope handling with gloves: Practice knots and coiling (10 minutes)',
'Sustained treadmill effort: 15% grade at 2.5mph for 30 minutes',
'Maintain effort: Drop to 12% grade, increase to 3.0mph for 30 minutes',
'Final push: 18% grade at 2.0mph for 30 minutes',
'Descent simulation: -10% grade treadmill, focus on control, 30 minutes',
'Quad-burning downhill steps: Slow eccentric step-downs x 100',
'Exhaustion box step-ups: Max reps in 5 minutes',
'Mental focus drill: Count backwards from 1000 by 7s while stepping',
'Recovery nutrition: Practice eating/drinking while moving (15 minutes)',
'Cool down walk: Gradually decrease intensity over 15 minutes'
]
},
{
id: 'anaerobic-threshold',
title: 'Anaerobic Threshold Builder',
difficulty: 'strenuous',
duration: 90,
description: 'High-intensity workout to improve anaerobic threshold',
exercises: [
'Easy jog: 5 minutes at conversational pace',
'Dynamic warm-up: High knees 30 seconds, butt kicks 30 seconds',
'Leg swings: 15 each direction per leg',
'Gradual pace increase: 5 minutes building to threshold',
'Threshold interval 1: 8 minutes at 85-90% max heart rate',
'Recovery: 3 minutes easy pace',
'Threshold interval 2: 8 minutes at 85-90% max heart rate',
'Recovery: 3 minutes easy pace',
'Threshold interval 3: 8 minutes at 85-90% max heart rate',
'Recovery: 3 minutes easy pace',
'Threshold interval 4: 8 minutes at 85-90% max heart rate',
'Recovery: 3 minutes easy pace',
'Hill sprints: 30 seconds all-out up steep incline',
'Recovery walk down: 90 seconds',
'Repeat hill sprints 7 more times',
'Tempo stair climbing: 10 minutes at 80% effort',
'Cool down jog: 5 minutes easy pace',
'Walking: 5 minutes with arm swings'
]
},
// EXPEDITION-SPECIFIC TRAINING
{
id: 'cold-weather-conditioning',
title: 'Cold Weather Conditioning',
difficulty: 'moderate',
duration: 120,
description: 'Training to prepare for extreme cold conditions',
exercises: [
'Indoor layer practice: Base, mid, shell in proper order (5 minutes)',
'Zipper and ventilation management while moving (5 minutes)',
'Jumping jacks: 50 reps',
'Mountain climbers: 50 reps',
'Burpees: 30 reps',
'High knees: 60 seconds',
'Treadmill at moderate pace: Monitor body temperature for 15 minutes',
'Add mid-layer: Continue for 10 minutes, practice venting',
'Remove mid-layer while walking: Practice efficiency (5 minutes)',
'Steady state cardio: Find balance between warmth and sweating (15 minutes)',
'Hand exercises: Make fists, spread fingers, 50 reps',
'Foot exercises: Toe curls, ankle pumps, 50 reps each',
'Arm windmills: 30 seconds forward, 30 backward',
'Wim Hof breathing: 3 rounds of 30 breaths with retention',
'Cold exposure breathing: Slow nasal breathing for 5 minutes',
'Box breathing in cold: 5-5-5-5 pattern for 5 minutes',
'Practice tasks with expedition mitts: Tie knots, handle carabiners',
'Practice tasks with liner gloves: Adjust equipment, eat snacks',
'Gradual warm-up: Remove layers systematically over 10 minutes'
]
},
{
id: 'rope-team-simulation',
title: 'Rope Team Movement',
difficulty: 'moderate',
duration: 90,
description: 'Simulating movement as part of a rope team',
exercises: [
'Partner coordination walk: Match pace for 5 minutes',
'Mirror movements: Follow partner\'s steps exactly (5 minutes)',
'Synchronized marching: Call out "left, right" for 30 steps',
'Matched cadence stepping: 60 steps at slow pace',
'Matched cadence stepping: 60 steps at medium pace',
'Matched cadence stepping: 60 steps at varied pace',
'Communication drills: "Slack!", "Tension!", "Falling!" (5 minutes)',
'Hand signals practice while walking (5 minutes)',
'Whistle signals practice: One blast, two blasts, three blasts',
'Interval with stops: Walk 2 minutes, sudden stop and brace',
'Repeat stop drills 10 times with random timing',
'Tension management: Practice keeping consistent rope tension',
'Rest step on incline: Synchronized leg lock for 15 minutes',
'Pace counting: Both partners count to 100 steps, compare',
'Communication under exertion: Maintain conversation at high effort',
'Mock debrief: Discuss imaginary route conditions (5 minutes)',
'Cool down walk: Practice rope coiling while walking'
]
},
{
id: 'altitude-acclimatization-prep',
title: 'Pre-Acclimatization Protocol',
difficulty: 'moderate',
duration: 90,
description: 'Workout to prepare body for altitude acclimatization',
exercises: [
'Diaphragmatic breathing: Hand on belly, 10 deep breaths',
'Box breathing: 4-4-4-4 pattern for 5 minutes',
'Breath retention: Inhale, hold to comfort, exhale slowly x 5',
'Hypoxic intervals: 20 jumping jacks, hold breath 10 seconds',
'Recovery breathing: 30 seconds',
'Repeat hypoxic intervals 8 times',
'Steady state cardio: Nasal breathing only, 15 minutes',
'Rhythmic breathing: 3 steps inhale, 2 steps exhale for 15 minutes',
'High-rep circuit: 20 bodyweight squats',
'High-rep circuit: 20 push-ups',
'High-rep circuit: 20 lunges',
'High-rep circuit: 20 mountain climbers',
'Rest 60 seconds, repeat circuit 4 times',
'Walking meditation: Focus on breath for 5 minutes',
'Seated meditation: Visualize high altitude scenery for 5 minutes'
]
},
// MENTAL PREPARATION
{
id: 'mental-toughness-grind',
title: 'Mental Toughness Builder',
difficulty: 'strenuous',
duration: 180,
description: 'Monotonous, challenging workout to build mental resilience',
exercises: [
'Immediate start: No warm-up, straight to work',
'Brief shoulder rolls and ankle circles only (2 minutes)',
'Mental prep: Set intention for sustained focus (3 minutes)',
'Stairmaster at level 8: No entertainment, no music, 30 minutes',
'Continue Stairmaster: Count every 100 steps, 30 minutes',
'Continue Stairmaster: Focus only on breathing pattern, 30 minutes',
'Wall sit: 3 minutes (break into 30-second chunks if needed)',
'Rest 60 seconds',
'Wall sit: 3 minutes',
'Rest 60 seconds',
'Repeat wall sits 3 more times',
'Weighted plank (30lb plate): 2 minutes',
'Rest 30 seconds',
'Repeat weighted plank 4 more times',
'Treadmill at 15% incline, 2.5mph: Count backwards from 2000',
'Continue for full 60 minutes without checking time',
'Mental counting exercise: Count every left foot strike',
'Continue counting: Restart if you lose count (15 minutes)',
'Walk at 0% incline: 3 minutes',
'Light stretching: 2 minutes total'
]
},
// QUICK WORKOUTS
{
id: 'quick-strength-circuit',
title: 'Quick Strength Circuit',
difficulty: 'moderate',
duration: 30,
description: 'Fast-paced strength circuit for busy days',
exercises: [
'Jumping jacks: 30 seconds',
'Arm circles: 15 each direction',
'Leg swings: 10 each direction per leg',
'Circuit Round 1: Squats 20 reps',
'Circuit Round 1: Push-ups 15 reps',
'Circuit Round 1: Step-ups 20 per leg',
'Circuit Round 1: Pull-ups max reps',
'Circuit Round 1: Plank 60 seconds',
'Rest 60 seconds',
'Circuit Round 2: Repeat all exercises',
'Rest 60 seconds',
'Circuit Round 3: Repeat all exercises',
'Standing quad stretch: 30 seconds each leg',
'Chest opener stretch: 30 seconds',
'Overhead triceps stretch: 30 seconds each arm'
]
},
{
id: 'morning-mobility',
title: 'Morning Mobility Routine',
difficulty: 'easy',
duration: 30,
description: 'Quick mobility routine to start the day',
exercises: [
'Neck circles: 10 each direction',
'Shoulder circles: 15 forward, 15 backward',
'Arm circles: 15 small, 15 large each direction',
'Wrist circles: 15 each direction',
'Spinal waves: 10 cat-cow movements',
'Thoracic rotations: 10 each side',
'Hip circles: 10 each direction per leg',
'Knee circles: 10 each direction per leg',
'Ankle circles: 15 each direction per foot',
'World\'s greatest stretch: 5 per side',
'Inchworm to downward dog: 5 reps',
'Deep squat hold with rotation: 30 seconds',
'Single-leg balance: 30 seconds per leg',
'Single-leg balance with eyes closed: 20 seconds per leg',
'Cross-body toe touches: 10 per side',
'Bird dogs: 10 per side with 3-second holds',
'Dead bugs: 10 per side',
'Plank: 60 seconds',
'Side plank: 30 seconds each side',
'Deep belly breathing: 10 breaths',
'Box breathing: 5 rounds of 4-4-4-4',
'Visualization: Picture successful summit day (2 minutes)'
]
},
// TECHNIQUE FOCUS
{
id: 'efficient-movement-patterns',
title: 'Efficient Movement Patterns',
difficulty: 'moderate',
duration: 90,
description: 'Focus on energy-efficient movement techniques',
exercises: [
'Video analysis setup: Record baseline walking form (5 minutes)',
'Normal walking: Note natural cadence and form (5 minutes)',
'Rest step introduction: Lock back leg completely straight',
'Rest step practice: 50 steps focusing on full leg lock',
'Rest step on incline: 5% grade for 5 minutes',
'Rest step on incline: 10% grade for 5 minutes',
'Rest step on incline: 15% grade for 10 minutes',
'Pressure breathing: Sharp exhale with each step x 50 steps',
'Pressure breathing with rest step: Combine techniques for 5 minutes',
'Lock-step practice: Small steps, maintain rhythm for 100 steps',
'Lock-step on steep grade: 18% incline for 10 minutes',
'Three-point contact simulation: Hands on knees technique',
'Downhill plunge step: Controlled heel-first placement x 50',
'Downhill side-stepping: Reduce quad strain for 5 minutes',
'Switchback technique: Figure-8 pattern on flat ground',
'Video review: Compare to baseline, note improvements (5 minutes)',
'Mental rehearsal: Visualize perfect form (5 minutes)'
]
},
// PEAK TRAINING
{
id: 'peak-performance-test',
title: 'Peak Performance Test',
difficulty: 'strenuous',
duration: 120,
description: 'Maximum effort test to gauge expedition readiness',
exercises: [
'Dynamic warm-up: Full body mobility sequence (10 minutes)',
'Progressive loading: Light cardio building intensity (5 minutes)',
'Max weight step-up test: Find 3-rep max on 20" box',
'Record weight and rest 3 minutes',
'VO2 max stair test: Maximum floors climbed in 12 minutes',
'Record floors and rest 5 minutes',
'Loaded carry test: 50lb pack, max distance in 10 minutes',
'Record distance and rest 5 minutes',
'Technical circuit: Ladder footwork drill 60 seconds',
'Technical circuit: Balance beam with pack 60 seconds',
'Technical circuit: Precise foot placements on targets 60 seconds',
'Technical circuit: Quick direction changes 60 seconds',
'Rest 2 minutes, repeat technical circuit',
'Fatigue management: Hold perfect plank to failure',
'Recovery heart rate: Record HR at 1, 3, and 5 minutes post-effort',
'Cool down walk: Light movement for 10 minutes',
'Performance metrics review: Calculate improvements (5 minutes)',
'Training plan adjustment: Note weak areas for focus'
]
},
// GENERAL FITNESS - STRENGTH TRAINING
{
id: 'full-body-strength',
title: 'Full Body Strength Workout',
difficulty: 'moderate',
duration: 60,
description: 'Comprehensive strength training for overall fitness',
exercises: [
'Treadmill walk: 5 minutes at moderate pace',
'Arm circles: 20 forward, 20 backward',
'Leg swings: 15 each direction per leg',
'Bodyweight squats: 15 reps',
'Push-ups: 10 reps',
'Barbell back squats: 4 sets of 8-10 reps',
'Bench press: 4 sets of 8-10 reps',
'Deadlifts: 4 sets of 6-8 reps',
'Seated cable rows: 3 sets of 12 reps',
'Overhead press: 3 sets of 10 reps',
'Lat pulldown: 3 sets of 12 reps',
'Dumbbell lunges: 3 sets of 10 reps per leg',
'Plank: 3 sets of 60 seconds',
'Russian twists with medicine ball: 3 sets of 20 reps',
'Hamstring stretch: 30 seconds each leg',
'Quad stretch: 30 seconds each leg',
'Shoulder stretch: 30 seconds each arm'
]
},
{
id: 'upper-body-hypertrophy',
title: 'Upper Body Muscle Building',
difficulty: 'moderate',
duration: 90,
description: 'High-volume upper body workout for muscle growth',
exercises: [
'Arm circles: 15 each direction',
'Band pull-aparts: 20 reps',
'Light dumbbell presses: 15 reps',
'Barbell bench press: 4 sets of 10-12 reps',
'Incline dumbbell press: 3 sets of 12 reps',
'Cable chest flyes: 3 sets of 15 reps',
'Seated dumbbell shoulder press: 4 sets of 10 reps',
'Lateral raises: 3 sets of 15 reps',
'Front raises: 3 sets of 12 reps',
'Barbell curls: 4 sets of 10 reps',
'Hammer curls: 3 sets of 12 reps per arm',
'Tricep pushdowns: 4 sets of 12 reps',
'Overhead tricep extensions: 3 sets of 15 reps',
'Face pulls: 3 sets of 15 reps',
'Chest stretch: 60 seconds each side',
'Tricep stretch: 30 seconds each arm',
'Shoulder rolls: 20 forward, 20 backward'
]
},
{
id: 'lower-body-power',
title: 'Lower Body Power Development',
difficulty: 'strenuous',
duration: 90,
description: 'Explosive lower body training for power and strength',
exercises: [
'Dynamic leg swings: 15 each direction per leg',
'Walking lunges: 20 total steps',
'Jump squats: 2 sets of 10 reps',
'Box jumps: 3 sets of 8 reps',
'Power cleans: 5 sets of 3 reps',
'Barbell squats: 5 sets of 5 reps (heavy)',
'Bulgarian split squats: 3 sets of 8 reps per leg',
'Leg press: 4 sets of 12 reps',
'Walking lunges with dumbbells: 3 sets of 20 steps',
'Single-leg deadlifts: 3 sets of 10 reps per leg',
'Calf raises: 4 sets of 20 reps',
'Seated calf raises: 3 sets of 15 reps',
'Jump rope: 3 sets of 60 seconds',
'Foam rolling: Quads, hamstrings, calves (5 minutes)',
'Standing quad stretch: 60 seconds each leg',
'Seated hamstring stretch: 60 seconds each leg'
]
},
// GENERAL FITNESS - CARDIOVASCULAR
{
id: 'steady-state-cardio',
title: 'Classic Cardio Session',
difficulty: 'moderate',
duration: 60,
description: 'Traditional steady-state cardiovascular training',
exercises: [
'Light walking: 5 minutes',
'Dynamic stretching: Arm swings, leg swings (3 minutes)',
'Treadmill jog: Build to comfortable pace over 3 minutes',
'Steady running: Maintain conversational pace for 30 minutes',
'Incline walking: 5% grade at 3.5mph for 5 minutes',
'Cool down jog: Gradually decrease pace over 3 minutes',
'Walking: 2 minutes',
'Standing quad stretch: 30 seconds each leg',
'Calf stretch: 30 seconds each leg',
'Hamstring stretch: 30 seconds each leg'
]
},
{
id: 'interval-training',
title: 'Cardio Interval Training',
difficulty: 'strenuous',
duration: 60,
description: 'High-intensity interval training for cardiovascular fitness',
exercises: [
'Light jog: 5 minutes',
'Dynamic warm-up: High knees, butt kicks, leg swings (3 minutes)',
'Interval 1: 1 minute hard run, 2 minutes recovery jog',
'Interval 2: 1 minute hard run, 2 minutes recovery jog',
'Interval 3: 1 minute hard run, 2 minutes recovery jog',
'Interval 4: 1 minute hard run, 2 minutes recovery jog',
'Interval 5: 1 minute hard run, 2 minutes recovery jog',
'Interval 6: 1 minute hard run, 2 minutes recovery jog',
'Cool down jog: 5 minutes decreasing pace',
'Walking: 3 minutes',
'Standing forward fold: 60 seconds',
'Runner\'s lunge stretch: 30 seconds each side'
]
},
// GENERAL FITNESS - HIIT
{
id: 'hiit-circuit',
title: 'High-Intensity Circuit',
difficulty: 'strenuous',
duration: 30,
description: 'Fast-paced HIIT circuit for maximum calorie burn',
exercises: [
'Jumping jacks: 60 seconds',
'Dynamic stretching: 2 minutes',
'Circuit 1: Burpees 30 seconds, rest 30 seconds',
'Circuit 1: Mountain climbers 30 seconds, rest 30 seconds',
'Circuit 1: Jump squats 30 seconds, rest 30 seconds',
'Circuit 1: High knees 30 seconds, rest 30 seconds',
'Rest: 90 seconds',
'Circuit 2: Push-ups 30 seconds, rest 30 seconds',
'Circuit 2: Jumping lunges 30 seconds, rest 30 seconds',
'Circuit 2: Plank jacks 30 seconds, rest 30 seconds',
'Circuit 2: Skaters 30 seconds, rest 30 seconds',
'Rest: 90 seconds',
'Circuit 3: Box jumps 30 seconds, rest 30 seconds',
'Circuit 3: Battle ropes 30 seconds, rest 30 seconds',
'Circuit 3: Kettlebell swings 30 seconds, rest 30 seconds',
'Circuit 3: Bicycle crunches 30 seconds, rest 30 seconds',
'Cool down walk: 3 minutes',
'Light stretching: 3 minutes'
]
},
{
id: 'tabata-workout',
title: 'Tabata Training Session',
difficulty: 'strenuous',
duration: 30,
description: 'Intense Tabata protocol for conditioning',
exercises: [
'Light cardio: 3 minutes',
'Dynamic warm-up: 3 minutes',
'Tabata 1: Jump squats - 8 rounds of 20 sec work, 10 sec rest',
'Rest: 1 minute',
'Tabata 2: Push-ups - 8 rounds of 20 sec work, 10 sec rest',
'Rest: 1 minute',
'Tabata 3: Burpees - 8 rounds of 20 sec work, 10 sec rest',
'Rest: 1 minute',
'Tabata 4: Mountain climbers - 8 rounds of 20 sec work, 10 sec rest',
'Cool down walk: 3 minutes',
'Deep breathing: 2 minutes',
'Light stretching: 3 minutes'
]
},
// GENERAL FITNESS - BODYWEIGHT
{
id: 'bodyweight-strength',
title: 'No-Equipment Strength Workout',
difficulty: 'moderate',
duration: 60,
description: 'Complete bodyweight workout requiring no equipment',
exercises: [
'Arm circles: 15 each direction',
'Leg swings: 10 each direction per leg',
'Jumping jacks: 30 reps',
'Push-ups: 3 sets of 15-20 reps',
'Bodyweight squats: 3 sets of 20 reps',
'Pike push-ups: 3 sets of 10 reps',
'Bulgarian split squats: 3 sets of 12 reps per leg',
'Diamond push-ups: 3 sets of 10 reps',
'Single-leg glute bridges: 3 sets of 15 reps per leg',
'Tricep dips (on chair): 3 sets of 15 reps',
'Wall sit: 3 sets of 60 seconds',
'Superman holds: 3 sets of 30 seconds',
'Plank: 3 sets of 60 seconds',
'Side plank: 3 sets of 30 seconds each side',
'Cool down stretching: 5 minutes'
]
},
{
id: 'calisthenics-progression',
title: 'Calisthenics Skill Work',
difficulty: 'moderate',
duration: 60,
description: 'Progressive calisthenics for strength and skill development',
exercises: [
'Joint mobility: Wrists, shoulders, hips (5 minutes)',
'Scapular pulls: 3 sets of 10 reps',
'Negative pull-ups: 3 sets of 5 reps (5-second descent)',
'L-sit progression: 3 sets of 15-30 seconds',
'Handstand practice against wall: 5 sets of 30 seconds',
'Pseudo planche lean: 3 sets of 20 seconds',
'Pistol squat progression: 3 sets of 5 reps per leg',
'Muscle-up progression: 3 sets of 5 false grip rows',
'Dips: 3 sets of 10-15 reps',
'Dragon flag progression: 3 sets of 5 reps',
'Hollow body hold: 3 sets of 30 seconds',
'Arch body hold: 3 sets of 30 seconds',
'Front lever progression: 3 sets of 10 seconds',
'Skin the cat: 3 sets of 3 reps',
'Wrist conditioning: 3 minutes',
'Full body stretch: 5 minutes'
]
},
// GENERAL FITNESS - CORE
{
id: 'core-strength-basic',
title: 'Core Strength Fundamentals',
difficulty: 'easy',
duration: 30,
description: 'Foundation core workout for beginners',
exercises: [
'Cat-cow: 10 repetitions',
'Bird dogs: 10 reps each side',
'Dead bugs: 10 reps each side',
'Plank: 3 sets of 30 seconds',
'Side plank: 3 sets of 20 seconds each side',
'Glute bridges: 3 sets of 15 reps',
'Bicycle crunches: 3 sets of 20 reps',
'Russian twists (no weight): 3 sets of 20 reps',
'Leg raises: 3 sets of 10 reps',
'Superman: 3 sets of 12 reps',
'Mountain climbers: 3 sets of 20 reps',
'Child\'s pose: 60 seconds',
'Cobra stretch: 30 seconds',
'Seated forward fold: 60 seconds'
]
},
{
id: 'advanced-core-workout',
title: 'Advanced Core Challenge',
difficulty: 'strenuous',
duration: 60,
description: 'Intense core workout for advanced athletes',
exercises: [
'Dynamic warm-up: 5 minutes',
'Hanging leg raises: 4 sets of 12 reps',
'Ab wheel rollouts: 4 sets of 10 reps',
'Dragon flags: 3 sets of 5 reps',
'Weighted Russian twists: 4 sets of 20 reps',
'Decline sit-ups with weight: 3 sets of 15 reps',
'Plank to pike on stability ball: 3 sets of 12 reps',
'L-sit holds: 3 sets of 20 seconds',
'Side plank with hip dips: 3 sets of 15 reps each side',
'Pallof press: 3 sets of 12 reps each side',
'Turkish get-ups: 3 sets of 3 reps each side',
'Hollow body rocks: 3 sets of 30 seconds',
'V-ups: 3 sets of 15 reps',
'Cool down stretching: 5 minutes'
]
},
// GENERAL FITNESS - FLEXIBILITY
{
id: 'full-body-flexibility',
title: 'Complete Flexibility Routine',
difficulty: 'easy',
duration: 60,
description: 'Comprehensive stretching for overall flexibility',
exercises: [
'Light cardio warm-up: 5 minutes',
'Neck rolls: 10 each direction',
'Shoulder rolls: 15 forward, 15 backward',
'Arm circles: 15 each direction',
'Standing side bends: 10 each side',
'Standing forward fold: Hold 60 seconds',
'Standing quad stretch: 60 seconds each leg',
'Standing figure-4 stretch: 60 seconds each leg',
'Lunging hip flexor stretch: 60 seconds each side',
'Seated hamstring stretch: 60 seconds each leg',
'Butterfly stretch: 90 seconds',
'Seated spinal twist: 60 seconds each side',
'Cat-cow: 15 repetitions',
'Child\'s pose: 60 seconds',
'Cobra stretch: 60 seconds',
'Pigeon pose: 90 seconds each side',
'Lying spinal twist: 60 seconds each side',
'Happy baby pose: 60 seconds',
'Savasana: 3 minutes'
]
},
{
id: 'dynamic-mobility-flow',
title: 'Dynamic Mobility Flow',
difficulty: 'moderate',
duration: 30,
description: 'Flowing movement sequence for mobility and flexibility',
exercises: [
'Joint circles sequence: Ankles, knees, hips, spine, shoulders, neck',
'Sun salutation A: 3 rounds',
'World\'s greatest stretch: 5 reps each side',
'Cossack squats: 10 reps each side',
'Inchworm to push-up: 8 reps',
'Scorpion stretch: 8 reps each side',
'Threading the needle: 10 reps each side',
'Hip circles in tabletop: 10 each direction per leg',
'Downward dog to cobra flow: 10 repetitions',
'Lateral lunges with reach: 8 each side',
'Standing figure-8 hip circles: 10 each direction',
'Arm thread and reach: 8 each side',
'Deep squat with rotation: 10 alternating sides',
'Standing backbend: 5 reps with 3-second holds',
'Reverse prayer position: Hold 30 seconds',
'Deep breathing in child\'s pose: 2 minutes'
]
},
// GENERAL FITNESS - CIRCUIT TRAINING
{
id: 'metabolic-circuit',
title: 'Metabolic Conditioning Circuit',
difficulty: 'strenuous',
duration: 60,
description: 'High-intensity circuit for metabolic conditioning',
exercises: [
'Jump rope: 3 minutes',
'Dynamic stretching: 3 minutes',
'Circuit 1: Kettlebell swings 60 seconds',
'Circuit 1: Box jumps 60 seconds',
'Circuit 1: Battle ropes 60 seconds',
'Circuit 1: Burpees 60 seconds',
'Rest: 90 seconds',
'Circuit 2: Thrusters 60 seconds',
'Circuit 2: Renegade rows 60 seconds',
'Circuit 2: Jump squats 60 seconds',
'Circuit 2: Mountain climbers 60 seconds',
'Rest: 90 seconds',
'Circuit 3: Clean and press 60 seconds',
'Circuit 3: Plank jacks 60 seconds',
'Circuit 3: Skater jumps 60 seconds',
'Circuit 3: Medicine ball slams 60 seconds',
'Rest: 90 seconds',
'Repeat all circuits once more',
'Cool down walk: 3 minutes',
'Stretching: 5 minutes'
]
},
{
id: 'full-body-circuit',
title: 'Total Body Circuit Training',
difficulty: 'moderate',
duration: 60,
description: 'Balanced circuit targeting all major muscle groups',
exercises: [
'Light cardio: 5 minutes',
'Dynamic warm-up: 5 minutes',
'Station 1: Push-ups 60 seconds',
'Station 2: Bodyweight squats 60 seconds',
'Station 3: Dumbbell rows 60 seconds',
'Station 4: Lunges 60 seconds',
'Station 5: Plank 60 seconds',
'Rest: 2 minutes',
'Station 6: Dips 60 seconds',
'Station 7: Step-ups 60 seconds',
'Station 8: Pull-ups or lat pulldown 60 seconds',
'Station 9: Deadlifts 60 seconds',
'Station 10: Bicycle crunches 60 seconds',
'Rest: 2 minutes',
'Repeat entire circuit once more',
'Cool down: 5 minutes stretching'
]
}
];

30
src/hooks/useTheme.ts Normal file
View file

@ -0,0 +1,30 @@
'use client';
import { useEffect, useState } from 'react';
export function useTheme() {
const [isDarkMode, setIsDarkMode] = useState(false);
const [mounted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
const savedTheme = localStorage.getItem('darkMode');
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
if (savedTheme === 'true' || (savedTheme === null && prefersDark)) {
setIsDarkMode(true);
document.body.classList.add('dark-mode');
}
}, []);
const toggleTheme = () => {
setIsDarkMode(prev => {
const newValue = !prev;
document.body.classList.toggle('dark-mode', newValue);
localStorage.setItem('darkMode', String(newValue));
return newValue;
});
};
return { isDarkMode, toggleTheme, mounted };
}

39
src/types/index.ts Normal file
View file

@ -0,0 +1,39 @@
export interface Project {
id: string;
title: string;
description: string;
sourceUrl: string;
}
export interface Skill {
category: string;
items: string[];
}
export interface SocialLink {
name: string;
url: string;
icon?: string;
}
export interface Experience {
company: string;
location: string;
positions: {
title: string;
date: string;
bullets?: string[];
}[];
}
export type WorkoutDifficulty = 'recovery' | 'easy' | 'moderate' | 'strenuous';
export type WorkoutDuration = 30 | 60 | 90 | 120 | 150 | 180 | 210 | 240 | 270 | 300;
export interface Workout {
id: string;
title: string;
difficulty: WorkoutDifficulty;
duration: WorkoutDuration;
exercises: string[];
description?: string;
}

50
tailwind.config.ts Normal file
View file

@ -0,0 +1,50 @@
import type { Config } from 'tailwindcss'
const config: Config = {
content: [
'./src/pages/**/*.{js,ts,jsx,tsx,mdx}',
'./src/components/**/*.{js,ts,jsx,tsx,mdx}',
'./src/app/**/*.{js,ts,jsx,tsx,mdx}',
],
theme: {
extend: {
colors: {
pink: {
50: '#FFF0F5',
100: '#FFE0EB',
200: '#FFB8D9',
300: '#FF8AC8',
400: '#F45D9E',
500: '#D23B80',
},
sage: {
200: '#D4E6D5',
300: '#B5D4B7',
400: '#8AB68C',
500: '#6A9A6C',
},
cream: {
50: '#FFFEF5',
100: '#FFF9F0',
},
},
spacing: {
'xs': '0.25rem',
'sm': '0.5rem',
'md': '1rem',
'lg': '1.5rem',
'xl': '2rem',
'xxl': '3rem',
},
maxWidth: {
'container': '1200px',
},
transitionDuration: {
'transition': '200ms',
},
},
},
plugins: [],
}
export default config

27
tsconfig.json Normal file
View file

@ -0,0 +1,27 @@
{
"compilerOptions": {
"target": "es2017",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}