feat: enhance CV with project title links, experience durations, certifications, and improved navigation
## Project Title Links - Add projectName and projectDesc fields to Project struct - Split project titles to make only project name clickable - Update template logic for conditional title rendering - Apply changes to both English and Spanish versions ## Experience Duration Display - Restore duration calculation display in experience section - Move duration from date line to after company name - Style duration in light gray (#999) for subtle appearance - Calculate durations dynamically (e.g., "4 years 10 months") ## Certifications Section Enhancement - Add Codecademy Certifications (2022-2024) with AI Transformers and React courses - Add LinkedIn Learning Certifications (2019-2020) with 5 professional courses - Implement colored icon system with brand colors (purple, cyan, green, etc.) - Use responsibilities format matching Third Party Contributions layout - Reorder courses chronologically (most recent first) ## localStorage Improvements - Save CV length preference (short/long) - Save logos visibility preference (show/hide) - Save theme preference (default/clean) - Restore all preferences on page load ## Navigation UX Enhancements - Fix scroll positioning to show sections below action bar - Add keepHeaderVisible flag to maintain header visibility after navigation - Ensure smooth scrolling with proper offset calculations - Reset flag on scroll up to restore normal hide/show behavior ## Files Modified - internal/models/cv.go: Add ProjectName, ProjectDesc fields - templates/cv-content.html: Update project and experience rendering - static/css/main.css: Add duration-text styling - templates/index.html: Enhance scroll behavior and localStorage - data/cv-*.json: Add certifications, split project titles, reorder courses - static/images/courses/: Add codecademy.png, linkedin.png
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, caste, color, religion, or sexual
|
||||
identity and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
* Demonstrating empathy and kindness toward other people
|
||||
* Being respectful of differing opinions, viewpoints, and experiences
|
||||
* Giving and gracefully accepting constructive feedback
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the overall
|
||||
community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or advances of
|
||||
any kind
|
||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email address,
|
||||
without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||
decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official email address,
|
||||
posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement via GitHub issues
|
||||
or by contacting the project maintainer directly.
|
||||
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
|
||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||
unprofessional or unwelcome in the community.
|
||||
|
||||
**Consequence**: A private, written warning from community leaders, providing
|
||||
clarity around the nature of the violation and an explanation of why the
|
||||
behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series of
|
||||
actions.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or permanent
|
||||
ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
**Community Impact**: A serious violation of community standards, including
|
||||
sustained inappropriate behavior.
|
||||
|
||||
**Consequence**: A temporary ban from any sort of interaction or public
|
||||
communication with the community for a specified period of time. No public or
|
||||
private interaction with the people involved, including unsolicited interaction
|
||||
with those enforcing the Code of Conduct, is allowed during this period.
|
||||
Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within the
|
||||
community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.1, available at
|
||||
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
|
||||
|
||||
Community Impact Guidelines were inspired by
|
||||
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
|
||||
[https://www.contributor-covenant.org/translations][translations].
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
|
||||
[Mozilla CoC]: https://github.com/mozilla/diversity
|
||||
[FAQ]: https://www.contributor-covenant.org/faq
|
||||
[translations]: https://www.contributor-covenant.org/translations
|
||||
+296
@@ -0,0 +1,296 @@
|
||||
# Contributing to CV Site
|
||||
|
||||
First off, thank you for considering contributing to this project! This CV site is a personal project, but contributions are welcome to improve the template, fix bugs, or add features that others might find useful.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Code of Conduct](#code-of-conduct)
|
||||
- [How Can I Contribute?](#how-can-i-contribute)
|
||||
- [Reporting Bugs](#reporting-bugs)
|
||||
- [Suggesting Enhancements](#suggesting-enhancements)
|
||||
- [Pull Requests](#pull-requests)
|
||||
- [Development Setup](#development-setup)
|
||||
- [Style Guidelines](#style-guidelines)
|
||||
- [Go Code Style](#go-code-style)
|
||||
- [HTMX Patterns](#htmx-patterns)
|
||||
- [CSS Style](#css-style)
|
||||
- [Testing](#testing)
|
||||
- [Commit Messages](#commit-messages)
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
This project and everyone participating in it is governed by our [Code of Conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to the project maintainer.
|
||||
|
||||
## How Can I Contribute?
|
||||
|
||||
### Reporting Bugs
|
||||
|
||||
Before creating bug reports, please check existing issues to avoid duplicates. When creating a bug report, include as many details as possible:
|
||||
|
||||
**Bug Report Template:**
|
||||
|
||||
```markdown
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '...'
|
||||
3. See error
|
||||
|
||||
**Expected behavior**
|
||||
What you expected to happen.
|
||||
|
||||
**Environment:**
|
||||
- Go version: [e.g., 1.21.5]
|
||||
- OS: [e.g., macOS 14.0, Ubuntu 22.04]
|
||||
- Browser (if applicable): [e.g., Chrome 120, Firefox 121]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
```
|
||||
|
||||
### Suggesting Enhancements
|
||||
|
||||
Enhancement suggestions are welcome! Please create an issue with:
|
||||
|
||||
- **Clear title** describing the enhancement
|
||||
- **Detailed description** of the proposed functionality
|
||||
- **Use case** explaining why this would be useful
|
||||
- **Implementation ideas** (optional) if you have thoughts on how to implement it
|
||||
|
||||
### Pull Requests
|
||||
|
||||
1. **Fork the repository** and create your branch from `main`
|
||||
2. **Branch naming convention:**
|
||||
- `feature/description` - New features (e.g., `feature/add-dark-mode`)
|
||||
- `fix/description` - Bug fixes (e.g., `fix/pdf-export-fonts`)
|
||||
- `docs/description` - Documentation updates (e.g., `docs/update-readme`)
|
||||
- `refactor/description` - Code refactoring (e.g., `refactor/simplify-handlers`)
|
||||
|
||||
3. **Make your changes:**
|
||||
- Follow the [style guidelines](#style-guidelines)
|
||||
- Add tests if adding new functionality (see [Testing](#testing))
|
||||
- Update documentation as needed
|
||||
|
||||
4. **Test your changes:**
|
||||
- Run `make dev` to test locally
|
||||
- Test PDF export functionality
|
||||
- Test both English and Spanish versions
|
||||
- Test responsive design on different screen sizes
|
||||
|
||||
5. **Commit your changes** with clear commit messages (see [Commit Messages](#commit-messages))
|
||||
|
||||
6. **Push to your fork** and submit a pull request to the `main` branch
|
||||
|
||||
7. **Pull Request Template:**
|
||||
|
||||
```markdown
|
||||
**Description**
|
||||
Brief description of what this PR does.
|
||||
|
||||
**Type of change**
|
||||
- [ ] Bug fix (non-breaking change which fixes an issue)
|
||||
- [ ] New feature (non-breaking change which adds functionality)
|
||||
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
|
||||
- [ ] Documentation update
|
||||
|
||||
**How Has This Been Tested?**
|
||||
Describe the tests you ran and how to reproduce them.
|
||||
|
||||
**Checklist:**
|
||||
- [ ] My code follows the style guidelines of this project
|
||||
- [ ] I have performed a self-review of my own code
|
||||
- [ ] I have commented my code, particularly in hard-to-understand areas
|
||||
- [ ] I have made corresponding changes to the documentation
|
||||
- [ ] My changes generate no new warnings
|
||||
- [ ] I have tested the changes locally
|
||||
```
|
||||
|
||||
## Development Setup
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- **Go 1.21+** installed
|
||||
- **Git** for version control
|
||||
- **Make** (optional, but recommended)
|
||||
- **Chrome/Chromium** for PDF generation testing
|
||||
|
||||
### Setup Steps
|
||||
|
||||
1. **Clone your fork:**
|
||||
```bash
|
||||
git clone https://github.com/YOUR-USERNAME/cv.git
|
||||
cd cv
|
||||
```
|
||||
|
||||
2. **Install dependencies:**
|
||||
```bash
|
||||
go mod download
|
||||
```
|
||||
|
||||
3. **Set up environment:**
|
||||
```bash
|
||||
cp .env.example .env
|
||||
# Edit .env if needed
|
||||
```
|
||||
|
||||
4. **Run development server:**
|
||||
```bash
|
||||
make dev
|
||||
# Or: GO_ENV=development go run main.go
|
||||
```
|
||||
|
||||
5. **Open browser:**
|
||||
```
|
||||
http://localhost:1999
|
||||
```
|
||||
|
||||
### Useful Make Commands
|
||||
|
||||
- `make dev` - Run in development mode (hot-reload enabled)
|
||||
- `make build` - Build production binary
|
||||
- `make test` - Test endpoints (requires server running)
|
||||
- `make clean` - Remove build artifacts
|
||||
- `make help` - Show all available commands
|
||||
|
||||
## Style Guidelines
|
||||
|
||||
### Go Code Style
|
||||
|
||||
- **Follow standard Go conventions:**
|
||||
- Use `gofmt` to format code (runs automatically with most editors)
|
||||
- Run `go vet` to catch common mistakes
|
||||
- Use meaningful variable and function names
|
||||
- Add comments for exported functions and complex logic
|
||||
|
||||
- **Code organization:**
|
||||
- Keep handlers in `main.go` or separate handler files
|
||||
- Use the `internal/models` package for data structures
|
||||
- Keep utilities in appropriate packages
|
||||
|
||||
- **Error handling:**
|
||||
```go
|
||||
// Good
|
||||
if err != nil {
|
||||
log.Printf("Error loading CV data: %v", err)
|
||||
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// Avoid silent failures
|
||||
// Bad: ignoring errors without logging
|
||||
data, _ := loadCV()
|
||||
```
|
||||
|
||||
### HTMX Patterns
|
||||
|
||||
- **Use semantic HTML:**
|
||||
```html
|
||||
<!-- Good -->
|
||||
<button hx-get="/cv?lang=en" hx-target="#cv-content" hx-swap="innerHTML">
|
||||
English
|
||||
</button>
|
||||
|
||||
<!-- Avoid inline styles when possible -->
|
||||
```
|
||||
|
||||
- **Keep HTMX attributes organized:**
|
||||
- `hx-get/post` first
|
||||
- `hx-target` second
|
||||
- `hx-swap` third
|
||||
- Other attributes follow
|
||||
|
||||
- **Progressive enhancement:**
|
||||
- Ensure basic functionality works without JavaScript
|
||||
- HTMX should enhance, not be required
|
||||
|
||||
### CSS Style
|
||||
|
||||
- **Organization:**
|
||||
- Group related styles together
|
||||
- Use comments to separate sections
|
||||
- Keep selectors specific but not overly complex
|
||||
|
||||
- **Naming:**
|
||||
- Use semantic class names
|
||||
- Prefer descriptive names over abbreviations
|
||||
|
||||
- **Responsive design:**
|
||||
- Mobile-first approach
|
||||
- Use media queries for larger screens
|
||||
- Test on multiple screen sizes
|
||||
|
||||
## Testing
|
||||
|
||||
**Current State:** This project does not yet have automated tests. This is a known gap.
|
||||
|
||||
**When adding tests (future):**
|
||||
|
||||
- Write unit tests for new utility functions
|
||||
- Add integration tests for HTTP handlers
|
||||
- Test PDF generation functionality
|
||||
- Ensure tests pass before submitting PR:
|
||||
```bash
|
||||
go test ./...
|
||||
```
|
||||
|
||||
**Manual testing requirements:**
|
||||
|
||||
- Test both language versions (English/Spanish)
|
||||
- Test PDF export (both server-side and browser print)
|
||||
- Test responsive design (mobile, tablet, desktop)
|
||||
- Test in multiple browsers (Chrome, Firefox, Safari)
|
||||
- Verify console has no errors
|
||||
- Check network tab for failed requests
|
||||
|
||||
## Commit Messages
|
||||
|
||||
Use clear, descriptive commit messages following this format:
|
||||
|
||||
```
|
||||
type: brief description
|
||||
|
||||
Optional longer description explaining what and why (not how).
|
||||
|
||||
Fixes #123
|
||||
```
|
||||
|
||||
**Types:**
|
||||
- `feat:` - New feature
|
||||
- `fix:` - Bug fix
|
||||
- `docs:` - Documentation changes
|
||||
- `style:` - Code style changes (formatting, no logic change)
|
||||
- `refactor:` - Code refactoring
|
||||
- `perf:` - Performance improvements
|
||||
- `test:` - Adding or updating tests
|
||||
- `chore:` - Maintenance tasks, dependency updates
|
||||
|
||||
**Examples:**
|
||||
|
||||
```
|
||||
feat: add dark mode toggle
|
||||
|
||||
Add user preference for dark mode with localStorage persistence.
|
||||
Respects system preference on first visit.
|
||||
|
||||
Fixes #42
|
||||
```
|
||||
|
||||
```
|
||||
fix: correct PDF font rendering in headless Chrome
|
||||
|
||||
The custom Quicksand font wasn't loading properly in chromedp.
|
||||
Updated to wait for fonts to load before PDF generation.
|
||||
|
||||
Fixes #38
|
||||
```
|
||||
|
||||
## Questions?
|
||||
|
||||
Feel free to open an issue with the `question` label if you need help or clarification on anything!
|
||||
|
||||
## Thank You!
|
||||
|
||||
Your contributions help make this project better for everyone. Thank you for taking the time to contribute! 🎉
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 Juan Andrés Moreno Rubio
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,7 +1,29 @@
|
||||
# CV Site - Go + HTMX
|
||||
|
||||
[](https://go.dev/)
|
||||
[](https://htmx.org/)
|
||||
[](LICENSE)
|
||||
[](CONTRIBUTING.md)
|
||||
|
||||
**Modern, minimal curriculum vitae website** for Juan Andrés Moreno Rubio built with **Go** and **HTMX**.
|
||||
|
||||
A professional, bilingual CV site with server-side PDF generation, HTMX interactivity, and a clean paper design aesthetic. Perfect template for developers looking to create their own CV website with modern tech and minimal JavaScript.
|
||||
|
||||
## 📑 Table of Contents
|
||||
|
||||
- [Features](#-features)
|
||||
- [Demo](#-demo)
|
||||
- [Quick Start](#-quick-start)
|
||||
- [Updating Your CV](#-updating-your-cv)
|
||||
- [Export to PDF](#-export-to-pdf)
|
||||
- [Key Technologies](#-key-technologies)
|
||||
- [Documentation](#-documentation)
|
||||
- [Deployment](#-deployment)
|
||||
- [Customization](#-customization)
|
||||
- [Contributing](#-contributing)
|
||||
- [License](#-license)
|
||||
- [Support](#-support)
|
||||
|
||||
## 🚀 Features
|
||||
|
||||
- ✅ **Bilingual Support** - Spanish and English with instant switching (no page reload)
|
||||
@@ -13,24 +35,55 @@
|
||||
- ✅ **JSON-Based Content** - Easy to update without touching code
|
||||
- ✅ **AI Development Section** - Showcases modern AI-assisted development skills
|
||||
- ✅ **Fast & Lightweight** - Go backend with chromedp for PDF generation
|
||||
- ✅ **Security Hardened** - CSP headers, XSS protection, secure defaults
|
||||
- ✅ **Production Ready** - Docker support, systemd service, CI/CD workflows
|
||||
- ✅ **Developer Friendly** - Hot reload, clear code structure, comprehensive Makefile
|
||||
|
||||
## 📸 Demo
|
||||
|
||||
**Live Features:**
|
||||
- Single-page application with no page reloads
|
||||
- Instant language switching (English ↔ Spanish)
|
||||
- Professional PDF export with perfect font rendering
|
||||
- Responsive design from mobile to desktop
|
||||
- Clean paper aesthetic on gray background
|
||||
- Print-friendly layouts
|
||||
|
||||
**Note:** This is a personal CV site template. Fork it and customize the JSON files with your own information!
|
||||
|
||||
## 📋 Quick Start
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- **Go 1.21+** installed
|
||||
- **Chrome/Chromium** (for PDF generation)
|
||||
- **Make** (optional, recommended for easier development)
|
||||
|
||||
### Run
|
||||
### Installation & Run
|
||||
|
||||
\`\`\`bash
|
||||
# Build and run
|
||||
# Clone the repository
|
||||
git clone https://github.com/yourusername/cv.git
|
||||
cd cv
|
||||
|
||||
# Option 1: Using Make (recommended)
|
||||
make dev
|
||||
|
||||
# Option 2: Using Go directly
|
||||
go run main.go
|
||||
|
||||
# Option 3: Build and run binary
|
||||
go build -o cv-server && ./cv-server
|
||||
\`\`\`
|
||||
|
||||
Open **http://localhost:1999**
|
||||
### Access the Site
|
||||
|
||||
- 🇬🇧 English: http://localhost:1999/?lang=en
|
||||
- 🇪🇸 Spanish: http://localhost:1999/?lang=es
|
||||
Open **http://localhost:1999** in your browser
|
||||
|
||||
- 🇬🇧 **English version:** http://localhost:1999/?lang=en
|
||||
- 🇪🇸 **Spanish version:** http://localhost:1999/?lang=es
|
||||
|
||||
**Language switching** is instant via HTMX - no page reload required!
|
||||
|
||||
## 📄 Updating Your CV
|
||||
|
||||
@@ -66,11 +119,115 @@ No code changes needed - just refresh browser!
|
||||
|
||||
## 🎯 Key Technologies
|
||||
|
||||
- Backend: **Go** (stdlib net/http)
|
||||
- PDF Generation: **chromedp** (headless Chrome automation)
|
||||
- Frontend: **HTMX** 1.9.10
|
||||
- Styling: Custom **CSS** with Quicksand font
|
||||
- Data: **JSON** files
|
||||
- **Backend:** Go 1.21+ (stdlib `net/http`, graceful shutdown)
|
||||
- **PDF Generation:** chromedp (headless Chrome automation)
|
||||
- **Frontend:** HTMX 1.9.10 (hypermedia-driven interactions)
|
||||
- **Styling:** Custom CSS with Quicksand font from Google Fonts
|
||||
- **Data:** JSON files for easy content management
|
||||
- **Deployment:** Docker, systemd service, GitHub Actions CI/CD
|
||||
|
||||
## 📚 Documentation
|
||||
|
||||
- **[ARCHITECTURE.md](ARCHITECTURE.md)** - System design, data flow, and technical decisions
|
||||
- **[CONTRIBUTING.md](CONTRIBUTING.md)** - How to contribute (issues, PRs, code style)
|
||||
- **[SECURITY.md](SECURITY.md)** - Security policy, vulnerability reporting, deployment considerations
|
||||
- **[CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)** - Community guidelines and standards
|
||||
- **[LICENSE](LICENSE)** - MIT License
|
||||
|
||||
## 🚀 Deployment
|
||||
|
||||
This project is production-ready with multiple deployment options:
|
||||
|
||||
### Docker Deployment
|
||||
|
||||
\`\`\`bash
|
||||
# Build Docker image
|
||||
make docker-build
|
||||
|
||||
# Run container
|
||||
make docker-run
|
||||
\`\`\`
|
||||
|
||||
### Systemd Service
|
||||
|
||||
\`\`\`bash
|
||||
# Install as systemd service
|
||||
make install-service
|
||||
|
||||
# Update running service
|
||||
make update-service
|
||||
\`\`\`
|
||||
|
||||
### Manual Deployment
|
||||
|
||||
\`\`\`bash
|
||||
# Build optimized binary
|
||||
make build
|
||||
|
||||
# Run in production mode
|
||||
GO_ENV=production ./cv-server
|
||||
\`\`\`
|
||||
|
||||
**Environment Configuration:** Copy `.env.example` to `.env` and customize:
|
||||
- `PORT` - Server port (default: 1999)
|
||||
- `GO_ENV` - Environment (development/production)
|
||||
- `TEMPLATE_HOT_RELOAD` - Enable template hot-reload in development
|
||||
|
||||
**Security:** See [SECURITY.md](SECURITY.md) for production deployment best practices.
|
||||
|
||||
## 🎨 Customization
|
||||
|
||||
### Update Your CV Content
|
||||
|
||||
1. Edit `data/cv-en.json` and `data/cv-es.json` with your information
|
||||
2. No code changes required - just refresh the browser!
|
||||
|
||||
### Customize Styling
|
||||
|
||||
- **Main styles:** `static/css/main.css`
|
||||
- **Colors:** Modify CSS variables in `:root` selector
|
||||
- **Fonts:** Update Google Fonts import in HTML templates
|
||||
- **Layout:** Edit templates in `templates/` directory
|
||||
|
||||
### Add New Sections
|
||||
|
||||
1. Update the `CV` struct in `internal/models/cv.go`
|
||||
2. Add content to JSON files in `data/`
|
||||
3. Update templates in `templates/` to display new sections
|
||||
|
||||
## 🤝 Contributing
|
||||
|
||||
Contributions are welcome! Whether it's:
|
||||
|
||||
- 🐛 Bug reports
|
||||
- 💡 Feature suggestions
|
||||
- 📝 Documentation improvements
|
||||
- 🔧 Code contributions
|
||||
|
||||
Please read [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines on:
|
||||
- Submitting issues
|
||||
- Creating pull requests
|
||||
- Code style and testing requirements
|
||||
- Development workflow
|
||||
|
||||
## 📄 License
|
||||
|
||||
This project is licensed under the **MIT License** - see the [LICENSE](LICENSE) file for details.
|
||||
|
||||
**TL;DR:** You can use this template for your own CV site, modify it, and distribute it. Just keep the original copyright notice.
|
||||
|
||||
## 💬 Support
|
||||
|
||||
- **Issues:** [GitHub Issues](https://github.com/yourusername/cv/issues) for bug reports and feature requests
|
||||
- **Discussions:** [GitHub Discussions](https://github.com/yourusername/cv/discussions) for questions and ideas
|
||||
- **Security:** See [SECURITY.md](SECURITY.md) for reporting security vulnerabilities
|
||||
|
||||
## 🙏 Acknowledgments
|
||||
|
||||
- **HTMX** - For making hypermedia-driven applications enjoyable
|
||||
- **chromedp** - For reliable headless Chrome automation
|
||||
- **Go Community** - For excellent standard library and tooling
|
||||
- **AI Assistance** - For accelerating development and documentation
|
||||
|
||||
---
|
||||
|
||||
|
||||
+205
@@ -0,0 +1,205 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
This project is actively maintained. Security updates will be provided for the latest release on the `main` branch.
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| main | :white_check_mark: |
|
||||
| < main | :x: |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
We take the security of this CV site seriously. If you discover a security vulnerability, please help us protect users by following responsible disclosure practices.
|
||||
|
||||
### How to Report
|
||||
|
||||
**DO NOT** open a public issue for security vulnerabilities.
|
||||
|
||||
Instead, please report security vulnerabilities by:
|
||||
|
||||
1. **GitHub Security Advisories** (Preferred):
|
||||
- Go to the repository's Security tab
|
||||
- Click "Report a vulnerability"
|
||||
- Fill out the form with details
|
||||
|
||||
2. **Direct Contact**:
|
||||
- Open a private issue or contact the maintainer directly
|
||||
- Use encrypted communication if the vulnerability is severe
|
||||
|
||||
### What to Include
|
||||
|
||||
Please provide the following information in your report:
|
||||
|
||||
- **Description** of the vulnerability
|
||||
- **Steps to reproduce** the issue
|
||||
- **Potential impact** (e.g., data exposure, XSS, CSRF)
|
||||
- **Affected versions** (if known)
|
||||
- **Suggested fix** (if you have one)
|
||||
- **Your contact information** for follow-up questions
|
||||
|
||||
### Response Timeline
|
||||
|
||||
- **Initial Response**: Within 48 hours
|
||||
- **Status Update**: Within 7 days
|
||||
- **Fix Timeline**: Depends on severity
|
||||
- Critical: Within 7 days
|
||||
- High: Within 14 days
|
||||
- Medium: Within 30 days
|
||||
- Low: Next release cycle
|
||||
|
||||
### Disclosure Policy
|
||||
|
||||
- We ask that you give us reasonable time to fix the vulnerability before public disclosure
|
||||
- We will credit you in the security advisory (unless you prefer to remain anonymous)
|
||||
- Once the fix is deployed, we will publish a security advisory with details
|
||||
|
||||
## Security Considerations for Deployments
|
||||
|
||||
If you're deploying this CV site, please be aware of these security considerations:
|
||||
|
||||
### 1. PDF Generation Security
|
||||
|
||||
The server uses headless Chrome (via chromedp) to generate PDFs:
|
||||
|
||||
- **Risk**: Chromedp executes JavaScript and renders HTML, which could be exploited if user input is not sanitized
|
||||
- **Mitigation**:
|
||||
- The CV data comes from trusted JSON files, not user input
|
||||
- If you modify the application to accept user input, ensure proper sanitization
|
||||
- Consider running chromedp in a sandboxed environment
|
||||
|
||||
### 2. Content Security Policy
|
||||
|
||||
The application includes CSP headers:
|
||||
|
||||
```go
|
||||
Content-Security-Policy: default-src 'self';
|
||||
script-src 'self' 'unsafe-inline' https://unpkg.com;
|
||||
style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;
|
||||
font-src 'self' https://fonts.gstatic.com;
|
||||
img-src 'self' data:
|
||||
```
|
||||
|
||||
- Review and adjust CSP headers based on your deployment needs
|
||||
- Remove `'unsafe-inline'` if possible by moving inline scripts/styles to separate files
|
||||
|
||||
### 3. Environment Variables
|
||||
|
||||
Sensitive configuration is managed via environment variables:
|
||||
|
||||
- **Never commit** `.env` file to version control
|
||||
- Use `.env.example` as a template
|
||||
- In production, use secure secret management (e.g., HashiCorp Vault, AWS Secrets Manager)
|
||||
|
||||
### 4. HTTPS in Production
|
||||
|
||||
- **Always use HTTPS** in production
|
||||
- Configure TLS certificates (Let's Encrypt recommended)
|
||||
- Consider using a reverse proxy (nginx, Caddy) for TLS termination
|
||||
|
||||
### 5. Rate Limiting
|
||||
|
||||
The application does not include built-in rate limiting:
|
||||
|
||||
- **Recommendation**: Use a reverse proxy (nginx, Caddy) to implement rate limiting
|
||||
- Protect the `/export/pdf` endpoint to prevent PDF generation abuse
|
||||
|
||||
### 6. Input Validation
|
||||
|
||||
While this application primarily serves static CV data:
|
||||
|
||||
- If you extend it to accept user input, implement strict validation
|
||||
- Sanitize all inputs before rendering in templates
|
||||
- Use Go's `html/template` package (which auto-escapes) for HTML rendering
|
||||
|
||||
### 7. Dependency Management
|
||||
|
||||
Keep dependencies up to date:
|
||||
|
||||
```bash
|
||||
# Check for outdated dependencies
|
||||
go list -u -m all
|
||||
|
||||
# Update dependencies
|
||||
go get -u ./...
|
||||
go mod tidy
|
||||
```
|
||||
|
||||
### 8. Security Headers
|
||||
|
||||
The application sets security headers:
|
||||
|
||||
- `X-Content-Type-Options: nosniff`
|
||||
- `X-Frame-Options: DENY`
|
||||
- `X-XSS-Protection: 1; mode=block`
|
||||
- `Content-Security-Policy: ...`
|
||||
|
||||
Review and enhance these headers based on your deployment needs.
|
||||
|
||||
### 9. Logging and Monitoring
|
||||
|
||||
- Enable structured logging in production
|
||||
- Monitor for unusual patterns (e.g., excessive PDF generation requests)
|
||||
- Set up alerts for errors and anomalies
|
||||
|
||||
### 10. Docker Security
|
||||
|
||||
If deploying via Docker:
|
||||
|
||||
- Use official, minimal base images
|
||||
- Run container as non-root user
|
||||
- Scan images for vulnerabilities (e.g., `docker scan`, Trivy)
|
||||
- Keep base images updated
|
||||
|
||||
## Known Security Considerations
|
||||
|
||||
### PDF Generation Resource Usage
|
||||
|
||||
- **Issue**: PDF generation uses headless Chrome, which consumes significant CPU/memory
|
||||
- **Impact**: Potential DoS via excessive PDF generation requests
|
||||
- **Mitigation**:
|
||||
- Implement rate limiting on `/export/pdf` endpoint
|
||||
- Consider caching generated PDFs
|
||||
- Monitor resource usage
|
||||
|
||||
### Third-Party Dependencies
|
||||
|
||||
External dependencies loaded from CDNs:
|
||||
|
||||
- HTMX from `https://unpkg.com`
|
||||
- Google Fonts from `https://fonts.googleapis.com`
|
||||
|
||||
**Recommendation**: For production, consider:
|
||||
- Self-hosting these dependencies for better control
|
||||
- Using Subresource Integrity (SRI) hashes
|
||||
- Implementing a Content Security Policy
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
If you're forking this project for your own CV:
|
||||
|
||||
1. **Review all code** before deploying
|
||||
2. **Update personal information** in JSON files
|
||||
3. **Configure security headers** appropriate for your use case
|
||||
4. **Enable HTTPS** with valid certificates
|
||||
5. **Keep dependencies updated** regularly
|
||||
6. **Monitor application logs** for suspicious activity
|
||||
7. **Backup your data** regularly
|
||||
8. **Test security** before going live
|
||||
|
||||
## Security Updates
|
||||
|
||||
Security updates will be announced via:
|
||||
|
||||
- GitHub Security Advisories
|
||||
- Release notes on GitHub
|
||||
- Git commit messages tagged with `[SECURITY]`
|
||||
|
||||
## Contact
|
||||
|
||||
For security concerns, please contact the project maintainer via GitHub.
|
||||
|
||||
## Acknowledgments
|
||||
|
||||
We appreciate the security research community's efforts in responsibly disclosing vulnerabilities. Thank you for helping keep this project secure!
|
||||
@@ -664,6 +664,35 @@
|
||||
}
|
||||
],
|
||||
"courses": [
|
||||
{
|
||||
"title": "Codecademy Certifications",
|
||||
"institution": "Codecademy",
|
||||
"courseLogo": "codecademy.png",
|
||||
"location": "Online",
|
||||
"date": "2022-2024",
|
||||
"duration": "Various",
|
||||
"shortDescription": "Professional development courses in AI and modern web technologies through Codecademy's interactive learning platform.",
|
||||
"responsibilities": [
|
||||
"<iconify-icon icon='mdi:robot' width='60' height='60' class='default-company-icon' style='color: #9333EA;'></iconify-icon><div><strong>Intro to AI Transformers Course</strong> <em>April 2024</em>: Comprehensive introduction to transformer architecture and AI models, covering attention mechanisms, encoder-decoder structures, and practical applications in natural language processing</div>",
|
||||
"<iconify-icon icon='mdi:react' width='60' height='60' class='default-company-icon' style='color: #61DAFB;'></iconify-icon><div><strong>Learn React Course</strong> <em>March 2022</em>: Complete React framework training covering components, state management, hooks, lifecycle methods, and modern React development practices</div>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "LinkedIn Learning Certifications",
|
||||
"institution": "LinkedIn Learning",
|
||||
"courseLogo": "linkedin.png",
|
||||
"location": "Online",
|
||||
"date": "2019-2020",
|
||||
"duration": "Various",
|
||||
"shortDescription": "Professional development courses in SAP technologies, UX design, security, and data analytics through LinkedIn Learning's comprehensive training platform.",
|
||||
"responsibilities": [
|
||||
"<iconify-icon icon='mdi:book-open-page-variant' width='60' height='60' class='default-company-icon' style='color: #D97706;'></iconify-icon><div><strong>Aprende lectura rápida</strong> <em>April 2020</em>: Speed reading techniques and comprehension strategies for professional development and efficient information processing</div>",
|
||||
"<iconify-icon icon='mdi:cloud' width='60' height='60' class='default-company-icon' style='color: #0FAAFF;'></iconify-icon><div><strong>A Tour of the SAP Cloud Platform</strong> <em>February 2020</em>: Comprehensive overview of SAP Cloud Platform services, architecture, and integration capabilities for enterprise cloud solutions</div>",
|
||||
"<iconify-icon icon='mdi:android' width='60' height='60' class='default-company-icon' style='color: #3DDC84;'></iconify-icon><div><strong>Learning Android Security</strong> <em>February 2020</em>: Android security best practices, encryption methods, secure coding practices, and mobile application security fundamentals</div>",
|
||||
"<iconify-icon icon='mdi:account-group' width='60' height='60' class='default-company-icon' style='color: #EC4899;'></iconify-icon><div><strong>Persuasive UX: Creating Credibility</strong> <em>January 2020</em>: User experience design principles focused on building trust, credibility, and persuasive design patterns for web applications</div>",
|
||||
"<iconify-icon icon='mdi:database' width='60' height='60' class='default-company-icon' style='color: #3B82F6;'></iconify-icon><div><strong>Big Data Foundations: Techniques and Concepts</strong> <em>December 2019</em>: Fundamentals of big data technologies, distributed computing, data processing frameworks, and analytics techniques</div>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Servoy World 2011",
|
||||
"institution": "Servoy",
|
||||
@@ -738,6 +767,8 @@
|
||||
"projects": [
|
||||
{
|
||||
"title": "Somos Una Ola - Beach Cleaning Initiative",
|
||||
"projectName": "Somos Una Ola",
|
||||
"projectDesc": "Beach Cleaning Initiative",
|
||||
"url": "https://somosunaola.org",
|
||||
"projectLogo": "somosunaola.png",
|
||||
"location": "La Palma, Canary Islands",
|
||||
@@ -753,6 +784,8 @@
|
||||
},
|
||||
{
|
||||
"title": "Herrumbre Vivo Arte - Artist Portfolio Website",
|
||||
"projectName": "Herrumbre Vivo Arte",
|
||||
"projectDesc": "Artist Portfolio Website",
|
||||
"url": "https://herrumbrevivoarte.com",
|
||||
"projectLogo": "herrumbre-vivo.png",
|
||||
"location": "Fuencaliente, La Palma",
|
||||
@@ -768,6 +801,8 @@
|
||||
},
|
||||
{
|
||||
"title": "La Porra.club - Football Prediction Platform",
|
||||
"projectName": "La Porra.club",
|
||||
"projectDesc": "Football Prediction Platform",
|
||||
"url": "https://laporra.club",
|
||||
"projectLogo": "laporra.png",
|
||||
"gitRepoUrl": "/Users/txeo/laporra",
|
||||
@@ -784,6 +819,8 @@
|
||||
},
|
||||
{
|
||||
"title": "CDC Starter Kit - SAP Customer Data Cloud Demo",
|
||||
"projectName": "CDC Starter Kit",
|
||||
"projectDesc": "SAP Customer Data Cloud Demo",
|
||||
"url": "https://gigyademo.com/cdc-starter-kit/",
|
||||
"projectLogo": "sap.png",
|
||||
"location": "Online",
|
||||
|
||||
@@ -669,6 +669,35 @@
|
||||
}
|
||||
],
|
||||
"courses": [
|
||||
{
|
||||
"title": "Certificaciones Codecademy",
|
||||
"institution": "Codecademy",
|
||||
"courseLogo": "codecademy.png",
|
||||
"location": "Online",
|
||||
"date": "2022-2024",
|
||||
"duration": "Varios",
|
||||
"shortDescription": "Cursos de desarrollo profesional en IA y tecnologías web modernas a través de la plataforma de aprendizaje interactivo de Codecademy.",
|
||||
"responsibilities": [
|
||||
"<iconify-icon icon='mdi:robot' width='60' height='60' class='default-company-icon' style='color: #9333EA;'></iconify-icon><div><strong>Intro to AI Transformers Course</strong> <em>Abril 2024</em>: Introducción completa a la arquitectura de transformers y modelos de IA, cubriendo mecanismos de atención, estructuras encoder-decoder y aplicaciones prácticas en procesamiento de lenguaje natural</div>",
|
||||
"<iconify-icon icon='mdi:react' width='60' height='60' class='default-company-icon' style='color: #61DAFB;'></iconify-icon><div><strong>Learn React Course</strong> <em>Marzo 2022</em>: Formación completa en React framework cubriendo componentes, gestión de estado, hooks, métodos de ciclo de vida y prácticas modernas de desarrollo con React</div>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Certificaciones LinkedIn Learning",
|
||||
"institution": "LinkedIn Learning",
|
||||
"courseLogo": "linkedin.png",
|
||||
"location": "Online",
|
||||
"date": "2019-2020",
|
||||
"duration": "Varios",
|
||||
"shortDescription": "Cursos de desarrollo profesional en tecnologías SAP, diseño UX, seguridad y análisis de datos a través de la plataforma de formación integral de LinkedIn Learning.",
|
||||
"responsibilities": [
|
||||
"<iconify-icon icon='mdi:book-open-page-variant' width='60' height='60' class='default-company-icon' style='color: #D97706;'></iconify-icon><div><strong>Aprende lectura rápida</strong> <em>Abril 2020</em>: Técnicas de lectura rápida y estrategias de comprensión para desarrollo profesional y procesamiento eficiente de información</div>",
|
||||
"<iconify-icon icon='mdi:cloud' width='60' height='60' class='default-company-icon' style='color: #0FAAFF;'></iconify-icon><div><strong>A Tour of the SAP Cloud Platform</strong> <em>Febrero 2020</em>: Visión general completa de servicios de SAP Cloud Platform, arquitectura y capacidades de integración para soluciones empresariales en la nube</div>",
|
||||
"<iconify-icon icon='mdi:android' width='60' height='60' class='default-company-icon' style='color: #3DDC84;'></iconify-icon><div><strong>Learning Android Security</strong> <em>Febrero 2020</em>: Mejores prácticas de seguridad Android, métodos de encriptación, prácticas de codificación segura y fundamentos de seguridad de aplicaciones móviles</div>",
|
||||
"<iconify-icon icon='mdi:account-group' width='60' height='60' class='default-company-icon' style='color: #EC4899;'></iconify-icon><div><strong>Persuasive UX: Creating Credibility</strong> <em>Enero 2020</em>: Principios de diseño de experiencia de usuario enfocados en generar confianza, credibilidad y patrones de diseño persuasivo para aplicaciones web</div>",
|
||||
"<iconify-icon icon='mdi:database' width='60' height='60' class='default-company-icon' style='color: #3B82F6;'></iconify-icon><div><strong>Big Data Foundations: Techniques and Concepts</strong> <em>Diciembre 2019</em>: Fundamentos de tecnologías big data, computación distribuida, frameworks de procesamiento de datos y técnicas de análisis</div>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Servoy World 2011",
|
||||
"institution": "Servoy",
|
||||
@@ -743,6 +772,8 @@
|
||||
"projects": [
|
||||
{
|
||||
"title": "Somos Una Ola - Iniciativa de Limpieza de Playas",
|
||||
"projectName": "Somos Una Ola",
|
||||
"projectDesc": "Iniciativa de Limpieza de Playas",
|
||||
"url": "https://somosunaola.org",
|
||||
"projectLogo": "somosunaola.png",
|
||||
"location": "La Palma, Islas Canarias",
|
||||
@@ -758,6 +789,8 @@
|
||||
},
|
||||
{
|
||||
"title": "Herrumbre Vivo Arte - Sitio Web Portfolio de Artista",
|
||||
"projectName": "Herrumbre Vivo Arte",
|
||||
"projectDesc": "Sitio Web Portfolio de Artista",
|
||||
"url": "https://herrumbrevivoarte.com",
|
||||
"projectLogo": "herrumbre-vivo.png",
|
||||
"location": "Fuencaliente, La Palma",
|
||||
@@ -773,6 +806,8 @@
|
||||
},
|
||||
{
|
||||
"title": "La Porra.club - Plataforma de Predicción de Fútbol",
|
||||
"projectName": "La Porra.club",
|
||||
"projectDesc": "Plataforma de Predicción de Fútbol",
|
||||
"url": "https://laporra.club",
|
||||
"projectLogo": "laporra.png",
|
||||
"gitRepoUrl": "/Users/txeo/laporra",
|
||||
@@ -789,6 +824,8 @@
|
||||
},
|
||||
{
|
||||
"title": "CDC Starter Kit - Demo de SAP Customer Data Cloud",
|
||||
"projectName": "CDC Starter Kit",
|
||||
"projectDesc": "Demo de SAP Customer Data Cloud",
|
||||
"url": "https://gigyademo.com/cdc-starter-kit/",
|
||||
"projectLogo": "sap.png",
|
||||
"location": "Online",
|
||||
|
||||
@@ -101,6 +101,8 @@ type Language struct {
|
||||
|
||||
type Project struct {
|
||||
Title string `json:"title"`
|
||||
ProjectName string `json:"projectName,omitempty"` // Optional: linkable part of title
|
||||
ProjectDesc string `json:"projectDesc,omitempty"` // Optional: non-linkable description part
|
||||
URL string `json:"url"`
|
||||
ProjectLogo string `json:"projectLogo,omitempty"` // Optional logo filename
|
||||
GitRepoUrl string `json:"gitRepoUrl,omitempty"` // Optional git repository URL for dynamic dates
|
||||
|
||||
@@ -779,6 +779,11 @@ iconify-icon {
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.duration-text {
|
||||
color: #999;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.responsibilities {
|
||||
list-style: none;
|
||||
margin-top: 1rem;
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 8.7 KiB |
@@ -91,7 +91,7 @@
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="experience-content">
|
||||
<strong>{{.Position}}{{if .Company}} - {{if .CompanyURL}}<a href="{{.CompanyURL}}" target="_blank" rel="noopener noreferrer">{{.Company}}</a>{{else}}{{.Company}}{{end}}{{end}}</strong><br>
|
||||
<strong>{{.Position}}{{if .Company}} - {{if .CompanyURL}}<a href="{{.CompanyURL}}" target="_blank" rel="noopener noreferrer">{{.Company}}</a>{{else}}{{.Company}}{{end}}{{if .Duration}} <span class="duration-text">{{.Duration}}</span>{{end}}{{end}}</strong><br>
|
||||
<small>{{.StartDate}} / {{if .Current}}{{if eq $.Lang "es"}}presente{{else}}now{{end}}{{else}}{{.EndDate}}{{end}} - ({{.Location}})</small>
|
||||
|
||||
{{if .ShortDescription}}
|
||||
@@ -186,7 +186,13 @@
|
||||
</div>
|
||||
{{end}}
|
||||
<div class="project-content">
|
||||
<strong>{{if .URL}}<a href="{{.URL}}" target="_blank" rel="noopener noreferrer">{{.Title}}</a>{{else}}{{.Title}}{{end}}</strong><br>
|
||||
<strong>
|
||||
{{if .ProjectName}}
|
||||
{{if .URL}}<a href="{{.URL}}" target="_blank" rel="noopener noreferrer">{{.ProjectName}}</a>{{else}}{{.ProjectName}}{{end}}{{if .ProjectDesc}} - {{.ProjectDesc}}{{end}}
|
||||
{{else}}
|
||||
{{if .URL}}<a href="{{.URL}}" target="_blank" rel="noopener noreferrer">{{.Title}}</a>{{else}}{{.Title}}{{end}}
|
||||
{{end}}
|
||||
</strong><br>
|
||||
<small>{{if .StartDate}}{{.StartDate}}{{if .Current}}{{if .DynamicDate}} / {{.DynamicDate}}{{else}} / {{if eq $.Lang "es"}}presente{{else}}now{{end}}{{end}}{{end}}{{end}} - ({{.Location}})</small>
|
||||
|
||||
{{if .ShortDescription}}
|
||||
|
||||
+56
-13
@@ -277,15 +277,32 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Flag to keep header visible after navigation
|
||||
let keepHeaderVisible = false;
|
||||
|
||||
// Scroll to section smoothly
|
||||
function scrollToSection(sectionId) {
|
||||
event.preventDefault(); // Prevent default anchor behavior
|
||||
|
||||
const section = document.getElementById(sectionId);
|
||||
if (section) {
|
||||
const actionBarHeight = document.querySelector('.action-bar').offsetHeight;
|
||||
const menuHeight = document.querySelector('.navigation-menu').offsetHeight;
|
||||
const offset = actionBarHeight + (menuHeight || 0) + 20; // Add 20px padding
|
||||
// Ensure header is visible before scrolling
|
||||
const actionBar = document.querySelector('.action-bar');
|
||||
const navMenu = document.querySelector('.navigation-menu');
|
||||
actionBar.classList.remove('header-hidden');
|
||||
navMenu.classList.remove('header-hidden');
|
||||
|
||||
// Set flag to keep header visible
|
||||
keepHeaderVisible = true;
|
||||
|
||||
// Close menu after clicking
|
||||
navMenu.classList.remove('menu-open');
|
||||
document.querySelector('.hamburger-btn').setAttribute('aria-expanded', 'false');
|
||||
|
||||
// Wait a bit for header to be visible, then calculate offset
|
||||
setTimeout(() => {
|
||||
const actionBarHeight = actionBar.offsetHeight;
|
||||
const offset = actionBarHeight + 20; // Add 20px padding
|
||||
|
||||
const elementPosition = section.getBoundingClientRect().top;
|
||||
const offsetPosition = elementPosition + window.pageYOffset - offset;
|
||||
@@ -294,11 +311,7 @@
|
||||
top: offsetPosition,
|
||||
behavior: 'smooth'
|
||||
});
|
||||
|
||||
// Close menu after clicking
|
||||
const menu = document.getElementById('navigation-menu');
|
||||
menu.classList.remove('menu-open');
|
||||
document.querySelector('.hamburger-btn').setAttribute('aria-expanded', 'false');
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -348,9 +361,11 @@
|
||||
if (toggle.checked) {
|
||||
paper.classList.add('cv-long');
|
||||
paper.classList.remove('cv-short');
|
||||
localStorage.setItem('cv-length', 'long');
|
||||
} else {
|
||||
paper.classList.add('cv-short');
|
||||
paper.classList.remove('cv-long');
|
||||
localStorage.setItem('cv-length', 'short');
|
||||
}
|
||||
|
||||
// Restore scroll position after DOM updates
|
||||
@@ -368,8 +383,10 @@
|
||||
|
||||
if (toggle.checked) {
|
||||
paper.classList.add('show-logos');
|
||||
localStorage.setItem('cv-logos', 'show');
|
||||
} else {
|
||||
paper.classList.remove('show-logos');
|
||||
localStorage.setItem('cv-logos', 'hide');
|
||||
}
|
||||
|
||||
// Restore scroll position after DOM updates
|
||||
@@ -412,10 +429,31 @@
|
||||
}, 100);
|
||||
}
|
||||
|
||||
// Initialize with short version, logos enabled, and saved theme
|
||||
// Initialize with saved preferences or defaults
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
document.querySelector('.cv-paper').classList.add('cv-short');
|
||||
document.querySelector('.cv-paper').classList.add('show-logos');
|
||||
const paper = document.querySelector('.cv-paper');
|
||||
|
||||
// Restore CV length preference
|
||||
const savedLength = localStorage.getItem('cv-length') || 'short';
|
||||
if (savedLength === 'long') {
|
||||
paper.classList.add('cv-long');
|
||||
paper.classList.remove('cv-short');
|
||||
document.getElementById('lengthToggle').checked = true;
|
||||
} else {
|
||||
paper.classList.add('cv-short');
|
||||
paper.classList.remove('cv-long');
|
||||
document.getElementById('lengthToggle').checked = false;
|
||||
}
|
||||
|
||||
// Restore logos preference
|
||||
const savedLogos = localStorage.getItem('cv-logos') || 'show';
|
||||
if (savedLogos === 'show') {
|
||||
paper.classList.add('show-logos');
|
||||
document.getElementById('logoToggle').checked = true;
|
||||
} else {
|
||||
paper.classList.remove('show-logos');
|
||||
document.getElementById('logoToggle').checked = false;
|
||||
}
|
||||
|
||||
// Restore theme preference
|
||||
const savedTheme = localStorage.getItem('cv-theme') || 'default';
|
||||
@@ -436,10 +474,15 @@
|
||||
const currentScroll = window.pageYOffset || document.documentElement.scrollTop;
|
||||
const isMenuOpen = navMenu.classList.contains('menu-open');
|
||||
|
||||
// If scrolling up, reset the keepHeaderVisible flag
|
||||
if (currentScroll < lastScrollTop) {
|
||||
keepHeaderVisible = false;
|
||||
}
|
||||
|
||||
// Hide/show header based on scroll direction
|
||||
if (currentScroll > scrollThreshold) {
|
||||
if (currentScroll > lastScrollTop) {
|
||||
// Scrolling down - hide header
|
||||
if (currentScroll > lastScrollTop && !keepHeaderVisible) {
|
||||
// Scrolling down - hide header (only if keepHeaderVisible is false)
|
||||
actionBar.classList.add('header-hidden');
|
||||
// Only hide menu if it's open
|
||||
if (isMenuOpen) {
|
||||
|
||||
Reference in New Issue
Block a user