From aa0554f5ba713689dcbea900de50db2f70dbb7ef Mon Sep 17 00:00:00 2001 From: Fernando Tona Date: Mon, 6 Oct 2025 01:06:57 +0100 Subject: [PATCH 1/2] docs: restructure documentation files --- README.md | 46 ++------ docs/ARCHITECTURE.md | 204 ++++++++++++++++++++++++++++++++++ docs/CONTRIBUTING.md | 207 ++++------------------------------- docs/project-instructions.md | 71 ------------ 4 files changed, 239 insertions(+), 289 deletions(-) create mode 100644 docs/ARCHITECTURE.md delete mode 100644 docs/project-instructions.md diff --git a/README.md b/README.md index 2367c0a..9dc2b6e 100644 --- a/README.md +++ b/README.md @@ -33,30 +33,15 @@ **CI/CD:** GitHub Actions **Deployment:** GitHub Pages -## Quick Start - -### For Visitors - -Simply visit: **[fernandotonacoder.github.io](https://fernandotonacoder.github.io)** - -### For Developers +## Development Commands ```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 +npm install # Dependencies for Jest, ESLint and Prettier +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 ``` ## Project Structure @@ -72,21 +57,12 @@ src/ └── 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 +- **Quality Assurance** All checks must pass before merging +- **Branch Protection:** _main_ branch protected. Use feature branch and PR. ## Author @@ -95,8 +71,8 @@ npm run format:check # Check formatting with Prettier ## Documentation -- **[Technical Documentation](docs/project-instructions.md)** - Architecture and system internals -- **[Contributing Guide](docs/CONTRIBUTING.md)** - Development workflow and key decisions +- **[Architecture Guide](docs/ARCHITECTURE.md)** - How the system works and technical decisions +- **[Contributing Guide](docs/CONTRIBUTING.md)** - Development workflow and setup --- diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md new file mode 100644 index 0000000..4ec8fa5 --- /dev/null +++ b/docs/ARCHITECTURE.md @@ -0,0 +1,204 @@ +# Architecture + +## Overview + +Static site built with vanilla HTML, CSS, and JavaScript. No build tools, no frameworks. Just native browser APIs and Bootstrap 5 for layout. + +**Philosophy:** Keep it simple. Add complexity only when necessary. + +--- + +## Translation System + +### Why Custom? + +Could've used i18next, but that's 50KB+ for something I can do in ~100 lines. + +### How It Works + +**Language detection:** +1. localStorage (`language` key) - remembers user choice +2. Browser language (`navigator.language`) +3. Fallback to English + +**Translation keys:** +- Flat JSON: `{"title": "...", "role": "..."}` +- No nesting (keeps it simple) +- Same keys across all languages (en, es, fr, pt) + +**HTML usage:** +```html +

Default text

+Default +``` + +**SEO:** Updates ``, meta description, and Open Graph tags on language change. + +### Module Pattern + +Supports both browser and Jest: +```javascript +// Browser: global functions +if (typeof window !== "undefined") { + window.setLanguage = setLanguage; +} + +// Jest: CommonJS exports +if (typeof module !== "undefined" && module.exports) { + module.exports = { setLanguage, ... }; +} +``` + +No build step needed. Works everywhere. + +--- + +## Custom Language Selector + +Standard `<select>` can't do glassmorphism without hacky CSS. Custom dropdown gives full control. + +**Features:** +- Click outside to close +- Keyboard accessible +- Pure JavaScript (no libs) + +--- + +## CSS + +### Mobile-First + +Base styles = mobile. Enhance for desktop: +```css +.custom-select { width: 110px; } /* mobile */ + +@media (min-width: 992px) { + .custom-select { width: 150px; } /* desktop */ +} +``` + +### Design Tokens + +```css +:root { + --clr-navy: #070f2b; + --clr-gradient-mid: #3572ef; + --clr-linkedin: #2856c7; +} +``` + +**Glassmorphism:** +```css +background: rgba(255, 255, 255, 0.1); +backdrop-filter: blur(10px); +``` + +**SVG colors:** Use filters instead of multiple files: +```css +filter: brightness(0) invert(1); /* white */ +filter: brightness(0) invert(0); /* dark */ +``` + +--- + +## Testing + +### Coverage: ~90% + +**What's tested:** +- Translation loading (success + errors) +- DOM updates (textContent, alt, meta tags) +- localStorage integration +- Dropdown behavior + +**What's not:** +- Browser APIs (tested by browsers) +- Bootstrap (tested by Bootstrap) +- DOMContentLoaded listener (manual test) + +--- + +## Tooling + +### ESLint Flat Config + +ESLint 9+ requires it. Multiple environments need different globals: +- Browser JS: `setLanguage`, `getCurrentLanguage` +- Test files: `describe`, `test`, `expect` +- Node scripts: `module`, `require` + +### Prettier + +```json +{ + "singleQuote": false, + "trailingComma": "none", + "arrowParens": "always", + "tabWidth": 4 +} +``` + +Personal preference from C#/TypeScript background. + +### Jest + jsdom + +Need DOM APIs without a browser. Jest runs tests in Node.js with simulated DOM. + +--- + +## Deployment & CI/CD + +### GitHub Actions Workflow + +**On Pull Request:** +```yaml +- Format check (Prettier) +- Lint (ESLint) +- Tests (Jest with coverage) +- Upload coverage artifact +``` + +**On Push to Main:** +```yaml +- All PR checks +- Build (prepare src/ folder) +- Deploy to GitHub Pages +``` + +**Branch Protection:** Direct pushes to main are blocked. Must use PRs. + +### GitHub Pages + +**Configuration:** +- Source: GitHub Actions (not branch-based) +- Deploys: `./src` directory +- URL: https://fernandotonacoder.github.io + +No build step needed - just copy static files. + +--- + +## Performance + +- Async translation loading (non-blocking) +- Only loads selected language +- System fonts (no font loading) +- Total JS: ~250 lines +- Page load: < 1s on 3G + +--- + +## Adding Features + +### New Translation Key + +1. Add to all 4 locale files +2. Use `data-translate="key"` in HTML +3. Test manually + +### New Language + +1. Create `/locales/{code}.json` +2. Update `supportedLangs` in `translations.js` +3. Update `languageNames` in `custom-select.js` +4. Add HTML option diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 5bf6f0b..640e1fc 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -1,204 +1,45 @@ -# Contributing Guide +# Contributing -## Development Setup +## Setup ```bash -git clone https://github.com/fernandotonacoder/fernandotonacoder.github.io.git -cd fernandotonacoder.github.io npm install +open src/index.html # or python -m http.server 8000 -d src ``` -**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: +Branch protection is on. Use feature branches: ```bash -git checkout -b feature/your-feature +git checkout -b feature/my-feature # make changes -git add . -git commit -m "Description" -git push origin feature/your-feature -# Create PR on GitHub +git commit -m "description" +git push origin feature/my-feature +# Open PR ``` -**CI/CD Pipeline:** - -- **On PR:** Tests, linting, format checks -- **On merge to main:** Auto-deploys to GitHub Pages - ---- - -## Commands +## Development 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 `<title>`, `<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); +npm install # Dependencies for Jest, ESLint and Prettier +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 ``` -**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) - ---- +**New translation key:** +1. Add to all 4 locale files (en, es, fr, pt) +2. Use: `<p data-translate="key">Default</p>` -## Resources +**New language:** +1. Create `locales/{code}.json` +2. Update `supportedLangs` in `translations.js` +3. Update `languageNames` in `custom-select.js` +4. Add HTML option -- [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 +See [ARCHITECTURE.md](ARCHITECTURE.md) for technical details. diff --git a/docs/project-instructions.md b/docs/project-instructions.md deleted file mode 100644 index d5ee54d..0000000 --- a/docs/project-instructions.md +++ /dev/null @@ -1,71 +0,0 @@ -# Project Instructions - Fernando Tona Portfolio - -## Project Overview - -This is a **static portfolio website** built with vanilla HTML, CSS, and JavaScript, leveraging Bootstrap 5 for layout. The site features a **custom, lightweight Translation System** that supports English, Spanish, French, and Portuguese. The project is hosted on GitHub Pages at `fernandotonacoder.github.io`. - ---- - -## Architecture & Key Components - -### Translation System (`js/translations.js` + `locales/*.json`) - -This module manages all text updates, language detection, and metadata application without external libraries. - -- **Logic:** Language priority is checked in this order: **Local Storage (key: 'language') → Browser Language → Fallback to English**. -- **Data Structure:** Translations are stored in flat JSON files within the `/locales/` directory (e.g., `en.json`, `role`). -- **HTML Attributes:** Elements are updated using custom `data-translate` attributes: - - `data-translate="key"`: Updates element's **textContent**. - - `data-translate-alt="key"`: Updates the **alt** attribute (essential for images and accessibility). - - `data-translate-html="key"`: Updates **innerHTML** (supported, currently unused). -- **SEO/Metadata:** The system dynamically updates the page `<title>`, `<meta name="description">`, and Open Graph (`og:title`, `og:description`) tags on language change. -- **Performance:** Translations are loaded **asynchronously** (`async/await`) using the native `fetch` API. - -### Custom Dropdown (`js/custom-select.js`) - -This file implements the styled dropdown menu for language selection. - -- **UI Implementation:** Uses vanilla JavaScript to handle dropdown toggle and visual state management (`.open`, `.selected` classes). -- **Integration:** It integrates with the translation system by calling **`setLanguage(lang)`** from `translations.js` upon selection. -- **Language Names:** Display names (e.g., 'English', 'Español') are hardcoded in the `languageNames` object within this file. - -### CSS Architecture (`css/style.css`) - -The CSS follows a well-organized structure with clear separation of concerns. - -- **Color Scheme:** Uses **CSS Variables** defined in `:root` (e.g., `--clr-navy`, `--clr-linkedin`) for easy theme consistency. -- **Icon Styling Pattern:** Icons (SVGs) use CSS filters for color manipulation across different states: - - White icon on dark background: `filter: brightness(0) invert(1)` - - Dark icon on light background: `filter: brightness(0) invert(0)` -- **Visual Pattern:** Elements like the language selector implement a "Glassmorphism" effect using `rgba()` combined with `backdrop-filter: blur(10px)`. -- **Responsiveness:** Mobile-first approach using Bootstrap utility classes and media queries for specific adjustments below 992px and 576px. - ---- - -## Conventions & Development Workflow - -### Development Setup - -| Task | Detail | -| :------------------ | :------------------------------------------------------------------------------------------------------- | -| **Cross-Platform** | Developed and maintained across **Linux, Windows, and macOS**. | -| **Dependencies** | Requires **Node.js/NPM** to run development tooling (Jest). The core site is dependency-free. | -| **Local Testing** | The project is static: open `index.html` in the browser or use a simple HTTP server. | -| **Deployment** | Git push to the main branch auto-deploys via GitHub Pages. | -| **Version Control** | **`package-lock.json`** must be committed to Git to ensure dependency stability across all environments. | - -### Testing - -- **Unit Tests:** JavaScript logic (`translations.js`, `custom-select.js`) is validated by `*.test.js` files. -- **Execution:** Tests must be run using **Jest** via the NPM script: `npm test`. - -### Adding New Content - -- **New Translations:** - 1. Add the new key and value to **ALL** locale files (`en.json`, `es.json`, `fr.json`, `pt.json`). - 2. Apply the corresponding `data-translate="keyName"` attribute to the target HTML element. -- **New Languages:** - 1. Create a new locale file in `/locales/{lang-code}.json` with **all** existing translation keys. - 2. Add the language code to the `supportedLangs` array in `js/translations.js`. - 3. Add the language name to the `languageNames` object in `js/custom-select.js`. - 4. Add the option element to the HTML selector in `index.html`. From 46d80ac3bbc08a6fd9ff068a1088feeee89d63ca Mon Sep 17 00:00:00 2001 From: Fernando Tona <fernandotonamusic@gmail.com> Date: Mon, 6 Oct 2025 01:10:21 +0100 Subject: [PATCH 2/2] fix: formatting issue --- docs/ARCHITECTURE.md | 24 +++++++++++++++++++++--- docs/CONTRIBUTING.md | 2 ++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 4ec8fa5..204f2a5 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -17,19 +17,22 @@ Could've used i18next, but that's 50KB+ for something I can do in ~100 lines. ### How It Works **Language detection:** + 1. localStorage (`language` key) - remembers user choice 2. Browser language (`navigator.language`) 3. Fallback to English **Translation keys:** + - Flat JSON: `{"title": "...", "role": "..."}` - No nesting (keeps it simple) - Same keys across all languages (en, es, fr, pt) **HTML usage:** + ```html <p data-translate="role">Default text</p> -<img data-translate-alt="imageAlt" alt="Default"> +<img data-translate-alt="imageAlt" alt="Default" /> ``` **SEO:** Updates `<title>`, meta description, and Open Graph tags on language change. @@ -37,6 +40,7 @@ Could've used i18next, but that's 50KB+ for something I can do in ~100 lines. ### Module Pattern Supports both browser and Jest: + ```javascript // Browser: global functions if (typeof window !== "undefined") { @@ -58,6 +62,7 @@ No build step needed. Works everywhere. Standard `<select>` can't do glassmorphism without hacky CSS. Custom dropdown gives full control. **Features:** + - Click outside to close - Keyboard accessible - Pure JavaScript (no libs) @@ -69,11 +74,16 @@ Standard `<select>` can't do glassmorphism without hacky CSS. Custom dropdown gi ### Mobile-First Base styles = mobile. Enhance for desktop: + ```css -.custom-select { width: 110px; } /* mobile */ +.custom-select { + width: 110px; +} /* mobile */ @media (min-width: 992px) { - .custom-select { width: 150px; } /* desktop */ + .custom-select { + width: 150px; + } /* desktop */ } ``` @@ -88,12 +98,14 @@ Base styles = mobile. Enhance for desktop: ``` **Glassmorphism:** + ```css background: rgba(255, 255, 255, 0.1); backdrop-filter: blur(10px); ``` **SVG colors:** Use filters instead of multiple files: + ```css filter: brightness(0) invert(1); /* white */ filter: brightness(0) invert(0); /* dark */ @@ -106,12 +118,14 @@ filter: brightness(0) invert(0); /* dark */ ### Coverage: ~90% **What's tested:** + - Translation loading (success + errors) - DOM updates (textContent, alt, meta tags) - localStorage integration - Dropdown behavior **What's not:** + - Browser APIs (tested by browsers) - Bootstrap (tested by Bootstrap) - DOMContentLoaded listener (manual test) @@ -123,6 +137,7 @@ filter: brightness(0) invert(0); /* dark */ ### ESLint Flat Config ESLint 9+ requires it. Multiple environments need different globals: + - Browser JS: `setLanguage`, `getCurrentLanguage` - Test files: `describe`, `test`, `expect` - Node scripts: `module`, `require` @@ -151,6 +166,7 @@ Need DOM APIs without a browser. Jest runs tests in Node.js with simulated DOM. ### GitHub Actions Workflow **On Pull Request:** + ```yaml - Format check (Prettier) - Lint (ESLint) @@ -159,6 +175,7 @@ Need DOM APIs without a browser. Jest runs tests in Node.js with simulated DOM. ``` **On Push to Main:** + ```yaml - All PR checks - Build (prepare src/ folder) @@ -170,6 +187,7 @@ Need DOM APIs without a browser. Jest runs tests in Node.js with simulated DOM. ### GitHub Pages **Configuration:** + - Source: GitHub Actions (not branch-based) - Deploys: `./src` directory - URL: https://fernandotonacoder.github.io diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 640e1fc..4cf6fb1 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -33,10 +33,12 @@ npm run format:check # Check formatting with Prettier ## Adding Features **New translation key:** + 1. Add to all 4 locale files (en, es, fr, pt) 2. Use: `<p data-translate="key">Default</p>` **New language:** + 1. Create `locales/{code}.json` 2. Update `supportedLangs` in `translations.js` 3. Update `languageNames` in `custom-select.js`