diff --git a/README.md b/README.md new file mode 100644 index 0000000..2367c0a --- /dev/null +++ b/README.md @@ -0,0 +1,109 @@ +# Fernando Tona - Professional Profile + +[![CI/CD Pipeline](https://github.com/fernandotonacoder/fernandotonacoder.github.io/actions/workflows/ci-cd.yml/badge.svg)](https://github.com/fernandotonacoder/fernandotonacoder.github.io/actions/workflows/ci-cd.yml) +[![GitHub Pages](https://img.shields.io/badge/GitHub%20Pages-deployed-success?logo=github)](https://fernandotonacoder.github.io) +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) +![GitHub last commit](https://img.shields.io/github/last-commit/fernandotonacoder/fernandotonacoder.github.io) +![GitHub repo size](https://img.shields.io/github/repo-size/fernandotonacoder/fernandotonacoder.github.io) +[![Code Style: Prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://github.com/prettier/prettier) +[![Tested with Jest](https://img.shields.io/badge/tested_with-jest-99424f.svg?logo=jest)](https://github.com/facebook/jest) +![HTML5](https://img.shields.io/badge/HTML5-E34F26?logo=html5&logoColor=white) +![CSS3](https://img.shields.io/badge/CSS3-1572B6?logo=css3&logoColor=white) +![JavaScript](https://img.shields.io/badge/JavaScript-F7DF1E?logo=javascript&logoColor=black) + +> Professional profile website showcasing my expertise as a Software Developer. + +**Live Site:** [fernandotonacoder.github.io](https://fernandotonacoder.github.io) + +--- + +## Features + +- 🌍 Multi-language support (English, Spanish, French, Portuguese) +- Modern, responsive design with glassmorphism effects +- Lightweight vanilla JavaScript - no frameworks +- Fast static site hosted on GitHub Pages +- Well-tested with Jest +- SEO optimized with dynamic meta tags + +## Tech Stack + +**Frontend:** HTML5 • CSS3 • Vanilla JavaScript • Bootstrap 5 +**Development:** Jest • ESLint • Prettier +**CI/CD:** GitHub Actions +**Deployment:** GitHub Pages + +## Quick Start + +### For Visitors + +Simply visit: **[fernandotonacoder.github.io](https://fernandotonacoder.github.io)** + +### For Developers + +```bash +# Clone and install +git clone https://github.com/fernandotonacoder/fernandotonacoder.github.io.git +cd fernandotonacoder.github.io +npm install + +# Run tests and checks +npm test +npm run lint +npm run format:check + +# Open locally (Option 1: directly in browser) +open src/index.html + +# Or Option 2: with local server +python -m http.server 8000 -d src +``` + +## Project Structure + +``` +src/ +├── index.html # Main page +├── css/style.css # Styles +├── js/ +│ ├── translations.js # Multi-language system +│ ├── custom-select.js # Language selector +│ └── *.test.js # Unit tests +└── locales/ # Translation files (en, es, fr, pt) +``` + +## Development Commands + +```bash +npm test # Run tests with Jest +npm run lint # Check code quality with ESLint +npm run lint:fix # Auto-fix issues with ESLint +npm run format # Format code with Prettier +npm run format:check # Check formatting with Prettier +``` + +## CI/CD Pipeline + +- **On PR:** Runs tests, linting, and format checks +- **On Merge:** Deploys to GitHub Pages automatically +- **Branch Protection:** All checks must pass before merging + +## Author + +**Fernando Tona** +[Website](https://fernandotonacoder.github.io) • [LinkedIn](https://www.linkedin.com/in/fernandotona/) • [GitHub](https://github.com/fernandotonacoder) • fernandotonacoder@protonmail.com + +## Documentation + +- **[Technical Documentation](docs/project-instructions.md)** - Architecture and system internals +- **[Contributing Guide](docs/CONTRIBUTING.md)** - Development workflow and key decisions + +--- + +
+ +**⭐ Star this repo if you find it useful!** + +Made with ❤️ by Fernando Tona + +
diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md new file mode 100644 index 0000000..5bf6f0b --- /dev/null +++ b/docs/CONTRIBUTING.md @@ -0,0 +1,204 @@ +# Contributing Guide + +## Development Setup + +```bash +git clone https://github.com/fernandotonacoder/fernandotonacoder.github.io.git +cd fernandotonacoder.github.io +npm install +``` + +**Local development:** Open `src/index.html` in browser or use `python -m http.server 8000 -d src` + +--- + +## Workflow + +**Branch protection is enabled.** Always work on feature branches: + +```bash +git checkout -b feature/your-feature +# make changes +git add . +git commit -m "Description" +git push origin feature/your-feature +# Create PR on GitHub +``` + +**CI/CD Pipeline:** + +- **On PR:** Tests, linting, format checks +- **On merge to main:** Auto-deploys to GitHub Pages + +--- + +## Commands + +```bash +npm test # Run Jest tests +npm run lint # ESLint check +npm run lint:fix # Auto-fix linting issues +npm run format # Prettier format all files +npm run format:check # Check if formatted correctly +``` + +--- + +## Architecture Decisions + +### Translation System + +**Why custom instead of i18n library?** + +- No external dependencies +- Tiny footprint (~100 lines) +- Does exactly what we need, nothing more + +**Language detection priority:** + +1. localStorage (`language` key) +2. Browser language (`navigator.language`) +3. Fallback to English + +**Translation keys:** Flat structure in `/locales/*.json`. HTML elements use `data-translate` attributes: + +- `data-translate="key"` → Updates `textContent` +- `data-translate-alt="key"` → Updates `alt` attribute +- `data-translate-html="key"` → Updates `innerHTML` (supported but unused) + +**SEO:** Dynamically updates ``, `<meta name="description">`, and Open Graph tags on language change. + +### Custom Language Selector + +**Why not a normal `<select>`?** + +- Needed custom styling (glassmorphism effect) +- Better control over appearance +- Still accessible with keyboard navigation + +### CSS Architecture + +**Color scheme:** CSS variables in `:root` for easy theming + +**Icon colors:** SVG filters for color manipulation: + +```css +/* White icons on dark background */ +filter: brightness(0) invert(1); + +/* Dark icons on light background */ +filter: brightness(0) invert(0); +``` + +**Glassmorphism effect:** + +```css +background: rgba(255, 255, 255, 0.1); +backdrop-filter: blur(10px); +``` + +### ESLint Config + +**Why flat config (`eslint.config.mjs`)?** + +- ESLint 9+ requires it +- Different environments need different globals: + - Browser JS: `setLanguage`, `getCurrentLanguage` (custom globals) + - Test files: Jest globals (`describe`, `test`, `expect`) + - Jest config: Node.js globals (`module`) + +### Prettier Config + +**Why these settings?** + +- Double quotes, no trailing commas, always parens → Personal preference from TypeScript/C# background +- `tabWidth: 4` → Personal preference from C# background + +--- + +## Adding Features + +### New Translation + +1. Add key to **ALL** locale files (`en.json`, `es.json`, `fr.json`, `pt.json`) +2. Add `data-translate="yourKey"` to HTML element +3. Test in all languages + +### New Language + +1. Create `/locales/{lang}.json` with all existing keys +2. Update `supportedLangs` in `js/translations.js` +3. Update `languageNames` in `js/custom-select.js` +4. Add option to language selector in `index.html` +5. Write tests + +--- + +## Gotchas + +**Tests failing?** + +- Make sure JSON files don't have trailing commas (Prettier removes them automatically) +- Run `npm test -- --clearCache` if weird caching issues + +**Translations not loading?** + +- Check browser console for fetch errors +- Verify JSON is valid +- Check file paths are correct + +**Styles not applying?** + +- Hard refresh: `Ctrl+Shift+R` (Windows/Linux) or `Cmd+Shift+R` (Mac) + +**Can't push to main?** + +- That's intentional. Create a feature branch and PR. + +--- + +## Testing Strategy + +**What we test:** + +- Translation system: Loading, language switching, localStorage persistence +- Custom selector: UI interactions, language selection + +**What we don't test:** + +- Bootstrap components (already tested by Bootstrap) +- Browser APIs (fetch, localStorage) +- CSS styling + +**Coverage target:** No specific target, just test critical logic. + +--- + +## Design Tokens + +### Colors + +```css +--clr-navy: #001f3f; /* Primary background */ +--clr-blue-text: #2563eb; /* Accent text */ +--clr-linkedin: #0077b5; +--clr-github: #333; +``` + +### Spacing Scale (Bootstrap) + +`0` = 0, `1` = 4px, `2` = 8px, `3` = 16px, `4` = 24px, `5` = 48px + +### Breakpoints + +- Mobile first approach +- Key breakpoint: 992px (tablets → desktop) + +--- + +## Resources + +- [Jest Docs](https://jestjs.io/docs/getting-started) +- [ESLint Flat Config](https://eslint.org/docs/latest/use/configure/configuration-files) +- [Bootstrap 5](https://getbootstrap.com/docs/5.3/) +- [CSS Filter Generator](https://codepen.io/sosuke/pen/Pjoqqp) for SVG colors diff --git a/src/css/style.css b/src/css/style.css index 56f93d5..14d8d8d 100644 --- a/src/css/style.css +++ b/src/css/style.css @@ -64,20 +64,20 @@ a { /* Language Selector */ .language-selector-wrapper { position: absolute; - top: 20px; - right: 20px; + top: 10px; + right: 10px; z-index: 1000; } /* Custom Select Styles */ .custom-select { position: relative; - width: 150px; + width: 110px; } .custom-select-trigger { - padding: 10px 40px 10px 16px; - font-size: 15px; + padding: 8px 32px 8px 12px; + font-size: 13px; font-weight: 600; color: white; background-color: rgba(255, 255, 255, 0.15); @@ -88,8 +88,8 @@ a { transition: all 0.3s ease; background-image: url("../assets/images/arrow-down.svg"); background-repeat: no-repeat; - background-position: right 12px center; - background-size: 12px; + background-position: right 10px center; + background-size: 10px; user-select: none; } @@ -128,8 +128,8 @@ a { } .custom-option { - padding: 10px 16px; - font-size: 15px; + padding: 8px 12px; + font-size: 13px; font-weight: 600; color: white; cursor: pointer; @@ -151,9 +151,9 @@ a { /* Button icons */ .btn-icon { - width: 20px; - height: 20px; - margin-right: 8px; + width: 18px; + height: 18px; + margin-right: 6px; filter: brightness(0) invert(1); } @@ -162,8 +162,7 @@ a { display: flex; align-items: center; justify-content: center; - min-width: 130px; - width: 130px; + width: 100%; background-color: var(--clr-linkedin); color: var(--clr-white); border: 2px solid var(--clr-linkedin); @@ -191,8 +190,7 @@ a { display: flex; align-items: center; justify-content: center; - min-width: 130px; - width: 130px; + width: 100%; background-color: transparent; color: var(--clr-white); border: 2px solid var(--clr-white); @@ -224,59 +222,37 @@ a { 4. MEDIA QUERIES (RESPONSIVE) =================================== */ -/* Tablet and mobile (below 992px) */ -@media (max-width: 991.98px) { - .col-10.col-sm-8.col-lg-6 { - display: flex; - justify-content: center; - margin: 0 auto; +/* Desktop and up (992px and above) */ +@media (min-width: 992px) { + .btn-linkedin, + .btn-github-outline { + width: auto; + min-width: 140px; } - .col-10.col-sm-8.col-lg-6 img { - margin: 0 auto; - display: block; + .btn-icon { + width: 20px; + height: 20px; + margin-right: 8px; } - - .col-lg-6 { - text-align: center; - } - - .d-grid.gap-2.d-md-flex { - justify-content: center !important; - } -} - -/* Small mobile (below 576px) */ -@media (max-width: 575.98px) { - .container { - text-align: center; - } - - .btn { - margin: 0.25rem !important; - } - .language-selector-wrapper { - top: 10px; - right: 10px; - } - - .language-selector { - padding: 8px 35px 8px 12px; - font-size: 13px; + top: 20px; + right: 20px; } .custom-select { - width: 120px; + width: 150px; } .custom-select-trigger { - padding: 8px 35px 8px 12px; - font-size: 13px; + padding: 10px 40px 10px 16px; + font-size: 15px; + background-position: right 12px center; + background-size: 12px; } .custom-option { - padding: 8px 12px; - font-size: 13px; + padding: 10px 16px; + font-size: 15px; } } diff --git a/src/index.html b/src/index.html index 1faaa7a..e0dc549 100644 --- a/src/index.html +++ b/src/index.html @@ -55,17 +55,17 @@ </div> <div class="row flex-lg-row-reverse align-items-center g-5 py-5"> - <div class="col-10 col-sm-8 col-lg-6"> + <div class="col-12 col-sm-10 col-md-8 col-lg-6 mx-auto mx-lg-0 text-center"> <img src="./assets/images/fernando-tona-dev-pic.jpg" class="d-block mx-auto img-fluid" alt="Fernando Tona picture" data-translate-alt="imageAlt" - style="max-height: 450px; border-radius: 2%" + style="max-width: 350px; border-radius: 2%" loading="lazy" /> </div> - <div class="col-lg-6"> + <div class="col-lg-6 text-center text-lg-start"> <h1 class="display-5 fw-bold lh-1 mb-3" style="color: #070f2b"> Fernando Tona </h1> @@ -75,13 +75,13 @@ <h1 class="display-5 fw-bold lh-1 mb-3" style="color: #070f2b"> <p class="lead" style="color: white" data-translate="tagline"> Problem-Solver with a Musician's Discipline </p> - <div class="d-grid gap-2 d-md-flex justify-content-md-start"> + <div class="d-grid gap-2 d-lg-flex justify-content-lg-start"> <a href="https://linkedin.com/in/fernandotona" target="_blank" rel="noopener noreferrer" > - <button type="button" class="btn btn-linkedin btn-lg px-4 me-md-2"> + <button type="button" class="btn btn-linkedin btn-lg px-4"> <img src="./assets/images/linkedin.svg" alt="LinkedIn logo" @@ -95,10 +95,7 @@ <h1 class="display-5 fw-bold lh-1 mb-3" style="color: #070f2b"> target="_blank" rel="noopener noreferrer" > - <button - type="button" - class="btn btn-github-outline btn-lg px-4 me-md-2" - > + <button type="button" class="btn btn-github-outline btn-lg px-4"> <img src="./assets/images/github.svg" alt="GitHub logo"