5-4 - convert to next.js
This commit is contained in:
parent
432a72b2f2
commit
a23cb6f09c
32 changed files with 9050 additions and 371 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
node_modules
|
||||
.next
|
113
index.html
113
index.html
|
@ -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>©<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
5
next-env.d.ts
vendored
Normal 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
16
next.config.js
Normal 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
7185
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
28
package.json
Normal file
28
package.json
Normal 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"
|
||||
}
|
||||
}
|
177
resume.html
177
resume.html
|
@ -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>©<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>
|
49
script.js
49
script.js
|
@ -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';
|
||||
}
|
||||
});
|
|
@ -1,6 +1,4 @@
|
|||
/* CSS Variables */
|
||||
:root {
|
||||
/* Pink palette */
|
||||
--pink-50: #FFF0F5;
|
||||
--pink-100: #FFE0EB;
|
||||
--pink-200: #FFB8D9;
|
||||
|
@ -8,24 +6,20 @@
|
|||
--pink-400: #F45D9E;
|
||||
--pink-500: #D23B80;
|
||||
|
||||
/* Sage palette */
|
||||
--sage-200: #D4E6D5;
|
||||
--sage-300: #B5D4B7;
|
||||
--sage-400: #8AB68C;
|
||||
--sage-500: #6A9A6C;
|
||||
|
||||
/* Neutral palette */
|
||||
--cream-50: #FFFEF5;
|
||||
--cream-100: #FFF9F0;
|
||||
|
||||
/* Semantic colors */
|
||||
--text: #4a4a4a;
|
||||
--bg-primary: var(--pink-50);
|
||||
--bg-secondary: white;
|
||||
--accent-primary: var(--pink-400);
|
||||
--accent-secondary: var(--sage-400);
|
||||
|
||||
/* Spacing */
|
||||
--space-xs: 0.25rem;
|
||||
--space-sm: 0.5rem;
|
||||
--space-md: 1rem;
|
||||
|
@ -33,14 +27,10 @@
|
|||
--space-xl: 2rem;
|
||||
--space-xxl: 3rem;
|
||||
|
||||
/* Container */
|
||||
--container-max: 1200px;
|
||||
|
||||
/* Animation */
|
||||
--transition: 0.2s ease;
|
||||
}
|
||||
|
||||
/* Reset */
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
|
@ -49,7 +39,6 @@
|
|||
padding: 0;
|
||||
}
|
||||
|
||||
/* Base styles */
|
||||
body {
|
||||
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', sans-serif;
|
||||
line-height: 1.6;
|
||||
|
@ -68,7 +57,6 @@ body {
|
|||
padding: 0 var(--space-md);
|
||||
}
|
||||
|
||||
/* Accessibility */
|
||||
.skip-link {
|
||||
position: absolute;
|
||||
top: -40px;
|
||||
|
@ -96,7 +84,6 @@ body {
|
|||
border: 0;
|
||||
}
|
||||
|
||||
/* Typography */
|
||||
h1,
|
||||
h2,
|
||||
h3 {
|
||||
|
@ -135,13 +122,11 @@ a:focus {
|
|||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* Focus styles */
|
||||
:focus {
|
||||
outline: 3px solid var(--pink-300);
|
||||
outline-offset: 3px;
|
||||
}
|
||||
|
||||
/* Header & Navigation */
|
||||
header {
|
||||
background-color: var(--bg-primary);
|
||||
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);
|
||||
}
|
||||
|
||||
/* Main content */
|
||||
main {
|
||||
flex: 1;
|
||||
padding: var(--space-xxl) 0;
|
||||
|
@ -318,7 +302,6 @@ main {
|
|||
margin-left: var(--space-xs);
|
||||
}
|
||||
|
||||
/* Footer */
|
||||
footer {
|
||||
background-color: var(--pink-100);
|
||||
padding: var(--space-xl);
|
||||
|
@ -345,7 +328,6 @@ footer {
|
|||
display: inline-block;
|
||||
}
|
||||
|
||||
/* Dark mode */
|
||||
.dark-mode {
|
||||
--pink-50: #3A2A35;
|
||||
--pink-100: #59354B;
|
||||
|
@ -365,7 +347,6 @@ footer {
|
|||
background: linear-gradient(to right, var(--pink-400), transparent);
|
||||
}
|
||||
|
||||
/* Responsive design */
|
||||
@media (max-width: 768px) {
|
||||
.menu-toggle {
|
||||
display: flex;
|
||||
|
@ -430,10 +411,6 @@ footer {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* Resume header and contact info */
|
||||
.resume-header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
@ -448,7 +425,6 @@ footer {
|
|||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
/* Resume sections */
|
||||
.resume-section {
|
||||
background-color: var(--bg-secondary);
|
||||
border-radius: 0.75rem;
|
||||
|
@ -481,7 +457,6 @@ footer {
|
|||
background: linear-gradient(to right, var(--pink-400), transparent);
|
||||
}
|
||||
|
||||
/* Education and experience items */
|
||||
.education-item,
|
||||
.experience-item {
|
||||
margin-bottom: var(--space-lg);
|
||||
|
@ -528,7 +503,6 @@ footer {
|
|||
margin-bottom: var(--space-xs);
|
||||
}
|
||||
|
||||
/* Skills grid */
|
||||
.skills-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
||||
|
@ -547,7 +521,6 @@ footer {
|
|||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
/* Print styles */
|
||||
@media print {
|
||||
body {
|
||||
background-color: white;
|
||||
|
@ -577,7 +550,6 @@ footer {
|
|||
}
|
||||
}
|
||||
|
||||
/* Skill category headings */
|
||||
.skill-heading {
|
||||
font-size: 1.1rem;
|
||||
color: var(--accent-primary);
|
||||
|
@ -587,19 +559,15 @@ footer {
|
|||
padding-bottom: var(--space-xs);
|
||||
}
|
||||
|
||||
/* Make the first skill heading not have extra top margin */
|
||||
.skill-heading:first-of-type {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
/* Dark mode styling for skill headings */
|
||||
.dark-mode .skill-heading {
|
||||
border-bottom-color: var(--pink-300);
|
||||
}
|
||||
|
||||
/* Responsive adjustments for resume */
|
||||
@media (max-width: 768px) {
|
||||
|
||||
.education-header,
|
||||
.experience-header {
|
||||
flex-direction: column;
|
||||
|
@ -613,3 +581,77 @@ footer {
|
|||
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
26
src/app/layout.tsx
Normal 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
26
src/app/page.tsx
Normal 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'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
0
src/app/providers.tsx
Normal file
77
src/app/resume/page.tsx
Normal file
77
src/app/resume/page.tsx
Normal 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>
|
||||
);
|
||||
}
|
71
src/app/workouts/[id]/page.tsx
Normal file
71
src/app/workouts/[id]/page.tsx
Normal 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
55
src/app/workouts/page.tsx
Normal 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>
|
||||
);
|
||||
}
|
42
src/components/Footer/Footer.tsx
Normal file
42
src/components/Footer/Footer.tsx
Normal 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>©{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>
|
||||
);
|
||||
}
|
9
src/components/Header/Header.tsx
Normal file
9
src/components/Header/Header.tsx
Normal file
|
@ -0,0 +1,9 @@
|
|||
import { Navigation } from './Navigation';
|
||||
|
||||
export function Header() {
|
||||
return (
|
||||
<header>
|
||||
<Navigation />
|
||||
</header>
|
||||
);
|
||||
}
|
55
src/components/Header/Navigation.tsx
Normal file
55
src/components/Header/Navigation.tsx
Normal 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>
|
||||
);
|
||||
}
|
20
src/components/Header/ThemeToggle.tsx
Normal file
20
src/components/Header/ThemeToggle.tsx
Normal 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>
|
||||
);
|
||||
}
|
12
src/components/Icons/IconWrapper.tsx
Normal file
12
src/components/Icons/IconWrapper.tsx
Normal 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} />;
|
||||
}
|
16
src/components/ProjectCard/ProjectCard.tsx
Normal file
16
src/components/ProjectCard/ProjectCard.tsx
Normal 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>
|
||||
);
|
||||
}
|
34
src/components/Skills/SkillGrid.tsx
Normal file
34
src/components/Skills/SkillGrid.tsx
Normal 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>
|
||||
);
|
||||
}
|
39
src/components/WorkoutCard/WorkoutCard.tsx
Normal file
39
src/components/WorkoutCard/WorkoutCard.tsx
Normal 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>
|
||||
);
|
||||
}
|
58
src/components/WorkoutFilters/WorkoutFilters.tsx
Normal file
58
src/components/WorkoutFilters/WorkoutFilters.tsx
Normal 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
22
src/data/projects.ts
Normal 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
24
src/data/skills.ts
Normal 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
16
src/data/social.ts
Normal 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
992
src/data/workouts.ts
Normal 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
30
src/hooks/useTheme.ts
Normal 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
39
src/types/index.ts
Normal 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
50
tailwind.config.ts
Normal 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
27
tsconfig.json
Normal 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"]
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue