Commit Graph

32 Commits

Author SHA1 Message Date
juanatsap 982257b4c1 feat: update repo URL to repos.txeo.club/txeo/cv-site
Deploy CV Server / Pull and Restart (push) Failing after 0s
Test CV Site / Test on Go 1.25.1 (push) Failing after 0s
Migrate all user-facing links from GitHub to self-hosted Forgejo.
Go module imports unchanged (separate concern).
2026-05-20 18:30:25 +01:00
juanatsap 6204ffdd6c fix: chat uses second person (tú/you), footer text visible over background
- Chat suggestions and help modal questions now address Juan directly
- Footer text/links use white with text-shadow for readability over photos
2026-04-26 23:39:38 +01:00
juanatsap 4f558ac842 fix: replace Hyperscript with plain JS for chat interactions
The Hyperscript trigger/call commands couldn't reliably trigger HTMX
form submissions or call global JS functions. Moved all chat
interactions to plain JavaScript:

- toggleChatPanel(): open/close panel + icon swap
- sendChatQuestion(q): set input + htmx.trigger(form, 'submit')
- closeChatHelpAndAsk(q): close modal + open chat + send question
- htmx:afterRequest listener clears input after submit

Hyperscript kept only for site-wide patterns (closeOnBackdrop) that
work reliably.

Also: better error message for rate-limited API responses (429).
2026-04-08 14:11:11 +01:00
juanatsap 25ddfff0da feat: redesign help modal with accordion and clickable questions
- Replace flat list with <details>/<summary> accordion (5 categories)
- Questions are clickable: close modal → open chat → send question
- closeChatHelpAndAsk() helper bridges modal and chat panel
- Green accent on category icons and question hover
- Chevron arrows for expand/collapse state
- Dark theme support for all accordion elements
- Compact layout with no wasted space
2026-04-08 14:01:17 +01:00
juanatsap 94976e1c19 feat: help modal, comprehensive intelligence, fix right-side position
Position fix:
- Remove _chat.css @import from main.css (was overriding with old
  left:2rem cached version). Chat CSS now loaded only via head-styles.
- Button confirmed at right:2rem, bottom:6rem (above back-to-top)

Help modal:
- New chat-help-modal.html using same <dialog> pattern as shortcuts
- 6 organized categories: Experience, Technologies, Projects,
  Education, Skills, How it works
- Bilingual EN/ES with example questions per category
- ? button in header opens modal via commandfor/show-modal
- Removed inline help card (modal replaces it)

Intelligence:
- Comprehensive query strategy for 8 question types
- Technology queries always use cross-section search
- Company queries use experience without filter for full listing
- Agent knows CV site is built with Go/HTMX (bonus context)
- Skills report proficiency levels when technology found
2026-04-08 13:15:07 +01:00
juanatsap 44116eba5a refactor: use hyperscript event filtering and destructuring
- Use event filtering [key is 'Enter' or key is ' '] on PDF modal cards
- Remove handlePdfCardKey helper function (now inline)
- Use event destructuring on keydown(key, target, ctrlKey, metaKey, altKey)
- Cleaner, more idiomatic hyperscript patterns
2025-12-02 17:55:45 +00:00
juanatsap 3c49f8f7cf refactor: use idiomatic hyperscript selector syntax
Replace verbose document.getElementById() and document.querySelectorAll()
with cleaner hyperscript syntax:
- #id for ID selectors
- .class and the first .class for class selectors
- <selector/> query literals for complex selectors
- #{variable} for dynamic ID interpolation

Files changed:
- utils._hs: scrollHeight, details, footer buttons, scrollToSection
- zoom._hs: all zoom control element selectors (14 changes)
- pdf-modal._hs: modal selector
- keyboard._hs: dynamic toggle and modal selectors
- contact-modal.html: response div and modal close
- index.html: ninja-keys bar selector
2025-12-02 16:23:40 +00:00
juanatsap 6970606c42 refactor: simplify contact form timestamp with hyperscript + minimal JS
Replace 34-line IIFE/MutationObserver with:
- Hyperscript: on toggle if me.open call resetContactForm()
- 11-line resetContactForm() function

Also dispatches 'show' event from openModal() for ninja-keys integration.
All 7 contact form tests pass.
2025-12-02 16:00:00 +00:00
juanatsap 2dd0922a63 refactor: replace verbose JS with hyperscript for contact form timestamp
Removed 34 lines of JavaScript (IIFE, MutationObserver, DOMContentLoaded)
and replaced with 2 lines of hyperscript in the existing 'on show' handler.
2025-12-02 15:52:33 +00:00
juanatsap 2d3d3de8cd feat: lazy load ninja-keys + HTML Invoker Commands API
- Lazy load ninja-keys only on CMD+K press (0 requests on initial load)
- Use esm.sh bundled module (3 requests vs ~81 previously)
- Add esm.sh to CSP whitelist
- Implement HTML Invoker Commands API for modals:
  - commandfor="modal-id" + command="show-modal" for opening
  - commandfor="modal-id" + command="close" for closing
  - Removes need for onclick handlers on modal buttons
- Refactor index.html into layout partials (head, body-scripts)
- Add comprehensive tests for both features
2025-12-02 08:29:54 +00:00
juanatsap 9a848e8c53 feat: Add CMD+K command palette with ninja-keys integration
Implement a command palette accessible via CMD+K/Ctrl+K using the ninja-keys
web component. Features include:

- New /api/cmd-k endpoint serving dynamic CV entries (experiences, projects, courses)
- Language-aware responses with 1-hour cache headers
- Scroll-to-section functionality for quick navigation
- Enhanced keyboard shortcuts modal with CMD+K documentation
- Comprehensive test coverage for API and UI interactions

Also includes cleanup of deprecated debug test files and various UI polish
improvements to contact form, themes, and action bar components.
2025-12-01 13:03:06 +00:00
juanatsap f91a24ea9b feat: Add plain text CV endpoint and contact form with security
Plain text endpoint:
- Add /text route for plain text CV (for curl/AI crawlers)
- Use k3a/html2text library for HTML-to-text conversion
- Add Plain Text button to hamburger menu with UI translations

Contact form feature:
- Add ContactHandler with proper email service integration
- Add CSRF protection middleware
- Add rate limiting (5 submissions/hour per IP)
- Add honeypot and timing-based bot protection
- Add input validation with detailed error messages
- Add security logging middleware
- Add browser-only middleware for API protection

Code quality:
- Fix all golangci-lint errcheck warnings for w.Write calls
- Remove duplicate getClientIP functions
- Wire up ContactHandler in routes.Setup
2025-11-30 13:47:49 +00:00
juanatsap 9636b3659f refactor: Extract all hardcoded content to JSON files
- Move all bilingual text from templates to UI JSON (labels, buttons, modals)
- Move skills summary paragraph to CV JSON with HTML support
- Add new UI sections: navigation, viewControls, sections, footer, portfolio,
  pdfModal, shortcutsModal, infoModal, widgets
- Update Go structs to match expanded JSON structure
- Add template.HTML type for CV.SkillsSummary field
- Add JSON content validation test (70-json-content-validation.test.mjs)

Templates now contain only structural logic (CSS classes, HTML attributes)
while all user-visible text loads from JSON files for proper i18n support.
2025-11-30 10:13:37 +00:00
juanatsap fd734635d9 refactor: Extract modal backdrop close and scrollToTop to functions
- Add closeOnBackdrop(modal, evt) to utils._hs for modal backdrop clicks
- Add scrollToTop(evt) to utils._hs for smooth scroll to top
- Simplify 3 modal templates (shortcuts, info, pdf) from 4 lines to 1
- Simplify back-to-top button from 3 lines to 1
2025-11-30 06:33:42 +00:00
juanatsap ba44b435e7 refactor: Major hyperscript refactoring and JS elimination
Inline Hyperscript Refactoring:
- Body tag keyboard handlers: 20→8 lines (using helper functions)
- Zoom control handlers: 85→35 lines (using zoom._hs)
- PDF modal card selection: 90→6 lines (3 identical blocks eliminated)

New Hyperscript Files:
- zoom._hs: handleZoomInput, handleZoomReset, initZoomControl
- pdf-modal._hs: selectPdfCard, handlePdfCardKey

JavaScript Elimination (232 lines removed):
- cv-functions.js: REMOVED - hyperscript defs are globally available
- scroll-at-bottom-handler.js: REMOVED - duplicate of handleScroll()
- footer-buttons-interaction.js: REMOVED - moved to hyperscript

Added Tests:
- 32-hyperscript-multi-src.test.mjs: Verifies multi-file loading
- 33-keyboard-shortcuts-refactored.test.mjs: Keyboard shortcuts
- 34-hyperscript-refactor-comprehensive.test.mjs: Full test suite

Key Findings:
- No hyperscript multi-file bug in 0.9.14
- Hyperscript def statements are globally accessible
- Previous refactoring failures were syntax errors, not library bugs
2025-11-30 05:58:44 +00:00
juanatsap 531433f54c fix: Remove toast notification from PDF download flow
Simplified PDF download UX to use only the modal loading overlay,
removing the redundant toast notification that appeared when the modal
was closed during download. Updated tests to reflect the new behavior.

Changes:
- Removed toast trigger logic from PDF modal download function
- Removed modal close event listener for toast display
- Updated toast notification test expectations
- Fixed recommended card outline styling
2025-11-20 14:35:22 +00:00
juanatsap 2c7a467149 fix: PDF modal layout and loading state issues
- Reorder cards: Short → Default  → Extended (was Short → Extended → Default)
- Add cleanup to prevent stuck blur effect on modal reopen
- Use MutationObserver to reset loading state when modal opens
- Add close event listener to clear loading-active class

Fixes:
1. Default CV now displays in center position as intended
2. Modal no longer shows grey/faded content due to stuck loading-active class
2025-11-20 13:31:56 +00:00
juanatsap 810ee7955b fix: References section link corruption and download filename issues
**Issue 1: URL corruption in "See this CV in..." links**
- Bug: replaceYearPlaceholder used fmt.Sprintf on ALL URLs
- URLs like "/?lang=es" were corrupted to "/?lang=es%!(EXTRA string=2025)"
- Fix: Changed to strings.ReplaceAll("{{YEAR}}", year)
- Result: Only replaces actual {{YEAR}} placeholders, leaves other URLs intact

**Issue 2: Download filename not respected**
- Bug: Shortcut URLs (cv-jamr-2025-en.pdf) redirected with HTTP 301
- Browsers used original URL filename instead of Content-Disposition header
- Fix: Generate PDF directly in DefaultCVShortcut handler
- Result: Returns PDF with correct filename in Content-Disposition header

Files changed:
- internal/models/cv.go: Fixed replaceYearPlaceholder function
- internal/handlers/cv.go: Changed redirect to direct PDF generation

Both fixes verified:
- "See this CV in Spanish" link: href="/?lang=es" ✓
- Download link: filename=cv-jamr-2025-en.pdf ✓
2025-11-20 13:00:06 +00:00
juanatsap c88879b180 feat: Add loading overlay feedback for PDF downloads
UX Improvement:
- Added visual feedback during PDF generation process
- Users now see immediate response when clicking download button
- Clear communication about what's happening during the wait

New Features:
- Loading overlay with animated spinner
- Format-specific estimated generation times (Short: ~3s, Default: ~4s, Long: ~8s)
- Blur effect on modal background during loading
- Bilingual support (English/Spanish)
- Automatic modal close after download completes

CSS Updates (static/css/04-interactive/_modals.css):
- Added .pdf-loading-overlay with glassmorphism effect
- Spinning animation for loader (1s linear infinite)
- Fade-in animation (300ms)
- Accessibility: respects prefers-reduced-motion
- Background blur when loading active

HTML Updates (templates/partials/modals/pdf-modal.html):
- Loading overlay structure with spinner
- Dynamic loading messages based on selected format
- Enhanced downloadPDF() function with timing logic

Before: Click → silence → download appears
After: Click → overlay + spinner + estimate → download appears
2025-11-20 12:52:16 +00:00
juanatsap 66e06a6cb0 feat: Add year-aware PDF shortcut URLs + Default CV modal option
## Shortcut URLs
- New routes: /cv-jamr-{year}-{lang}.pdf (e.g., /cv-jamr-2025-en.pdf)
- Year validation: Only current year accepted, returns 404 for past/future
- Auto-redirects (301) to: /export/pdf?lang={lang}&length=short&icons=show&version=with_skills
- Both languages supported: en and es

## PDF Modal Updates
- Replaced "Current View" option with "Default CV (Recommended)"
- Visual highlighting: purple gradient badge, star emoji , bold text
- Uses shortcut URL with dynamic year detection
- Clear recommendation for users (5 pages, short with skills)

## Technical Details
- Handler: DefaultCVShortcut() in internal/handlers/cv.go
- Pattern check in Home() handler for proper routing
- Helper function: window.openPdfModal() for references section
- Documentation: PDF-SHORTCUT-IMPLEMENTATION.md

Benefits:
- Memorable, shareable URLs (juan.andres.morenorub.io/cv-jamr-2025-en.pdf)
- Auto-updates yearly without code changes
- Clear user guidance for recommended CV format
2025-11-20 12:14:53 +00:00
juanatsap b44f9b9a99 refactor: Rename 'extended' → 'long' + add compact sidebar fonts
BREAKING CHANGE: API parameter renamed from 'extended' to 'long'

## Breaking Change: Terminology Standardization

Renamed 'extended' to 'long' across entire codebase for consistency:

**Backend (Go):**
- internal/handlers/cv.go (7 locations)
  - Migration logic to auto-convert 'extended' → 'long' cookies
  - API validation now rejects 'extended', requires 'long'
  - Toggle state logic updated
- internal/handlers/pdf_test.go (17 occurrences)
  - Test function renamed: TestExportPDF_ExtendedWithSkills → TestExportPDF_LongWithSkills
  - All test cases, parameters, and expected filenames updated
- internal/pdf/generator.go (2 comment updates)

**Frontend:**
- PDF-EXPORT-FEATURE.md (3 occurrences)
- doc/3-API.md (parameter documentation)
- doc/7-CUSTOMIZATION.md (examples updated)
- templates/partials/modals/pdf-modal.html (button text, URLs)
- static/js/main.js (migration logic)
- static/hyperscript/toggles._hs (toggle logic)
- tests/mjs/24-pdf-download-params.test.mjs (test expectations)
- tests/mjs/test-preference-migration.test.mjs (NEW)
- tests/mjs/verify-migration.test.mjs (NEW)

**PDFs Renamed:**
- cv-extended-with_skills-jamr-2025-en.pdf → cv-long-with_skills-jamr-2025-en.pdf
- cv-extended-with_skills-jamr-2025-es.pdf → cv-long-with_skills-jamr-2025-es.pdf

**Migration:** Automatic cookie migration from 'extended' → 'long' for seamless UX

## New Feature: Compact Sidebar Fonts

Reduces page count for short CV with skills from 6 → 5 pages:

**Implementation:**
- Location: internal/pdf/generator.go (lines 154-215)
- Cookie detection: `cookies["cv-length"] == "short"`
- Font reduction: 2-6% (0.94-0.98em) - very subtle
- Only activates for: `length=short` + `version=with_skills`
- Long version: Always uses full-size fonts

**Impact:**
- Page count: 6 pages → 5 pages (16.7% reduction)
- Readability: Maintained - fonts remain professional
- Design philosophy: Subtle, natural content flow

**Testing:**
- New test: TestPDFGenerator_CompactSidebarFonts
- Comprehensive coverage of cookie detection and PDF generation
- Manual verification: 5-page PDF with compact but readable fonts

**Documentation:**
- doc/LONG-PDF-GENERATION.md (NEW, 13 KB)
  - Complete feature documentation
  - Implementation details with code examples
  - Font size breakdown table
  - Testing and troubleshooting guides
  - Compact sidebar fonts section (comprehensive)

**Files Changed:**
- 11 modified (backend + frontend + docs)
- 5 new files (2 PDFs, 1 doc, 2 tests)
- 2 files renamed (PDFs)

**Tests:** All Go tests passing, API validation verified, PDF generation tested
2025-11-20 11:21:43 +00:00
juanatsap 27f5e8eb79 docs: Rename PDF length parameter from 'detailed' to 'short'
Changed PDF export naming convention from 'detailed' to 'short' for better clarity and contrast with 'extended'. Updated:

- Documentation: All references from 'detailed' → 'short'
- JSON data files: Static PDF URLs now use cv-short-jamr-{{YEAR}}-{lang}.pdf
- Frontend modal: Removed 'short' → 'detailed' mapping (now stays as 'short')
- Static PDFs: Renamed cv-detailed-* to cv-short-* (deleted old files)
- Backend validation: Change
2025-11-19 17:40:06 +00:00
juanatsap 1837a9b0ae quick fix to prod 2025-11-19 17:27:39 +00:00
juanatsap 43414b79ac fix: Override inline icon sizes to 1.2em across all sections
Problem: Inline icons embedded in responsibilities, courses, and
projects had explicit width='60' height='60' attributes that made
them too large (60px instead of ~16px).

Solution:
- Added CSS with !important to override inline width/height attributes
- Targeted inline icons in:
  * Course responsibilities and descriptions
  * Project descriptions and technologies
  * Experience responsibilities (within divs)
- Preserved large icons (80px) for main company/course/project logos

Changes:
- static/css/03-components/_courses.css: Override to 1.2em
- static/css/03-components/_projects.css: Override to 1.2em
- static/css/03-components/_cv-section.css: Override to 1.2em

Test Results:
 7 course inline icons: 16px × 16px
 Main company icons: 80px × 80px (preserved)
2025-11-19 16:30:18 +00:00
juanatsap 35a802cbd5 fix: Keep sidebar background consistent across themes
Change sidebar background from var(--sidebar-bg) to fixed #d1d4d2
so it remains the same light gray color in both light and dark themes.

The sidebar should provide a consistent visual anchor regardless
of the main content theme.
2025-11-19 14:57:38 +00:00
juanatsap f7cda5dba3 refactor: Modularize CSS and fix theme-aware text colors
CSS Restructuring:
- Reorganize monolithic main.css into modular architecture
- Create foundation/ (reset, variables, typography, themes)
- Create layout/ (container, page, grid, paper)
- Create components/ (8 component files)
- Create interactive/ (toggles, remaining for future split)
- Create effects/ (skeleton loading)
- Create contexts/ (print styles)

Theme Support Fixes:
- Replace all hardcoded text colors with CSS variables
- Fix .section-title: rgb(51,51,51) → var(--text-primary)
- Fix .cv-name, .intro-text: hardcoded → theme-aware
- Fix .experience-period, .duration-text: #555/#aaa → variables
- Fix course/project/experience text colors
- Support proper light/dark theme text contrast

Icon & Layout Fixes:
- Standardize all icon sizes to 80×80px
- Change all icon backgrounds to transparent
- Fix award section layout (missing flexbox)
- Update HTML templates (experience.html, awards.html) to width='80'
- Fix default icon sizing conflicts

View Switcher Fix:
- Fix toggleTheme() to target .cv-container instead of body
- Ensures clean/default theme toggle works correctly

Files: 40+ CSS files modularized, 3 templates updated, 7 tests added
2025-11-19 14:31:17 +00:00
juanatsap 6e2b042c8d feat(pdf-modal): implement interactive thumbnail selection
Transform PDF modal from placeholder to functional UI with three
interactive thumbnail cards using skeleton/placeholder styling.

Features:
- Three thumbnail options: Short CV (1 page), Long CV (2 pages), Custom (coming soon)
- Skeleton shimmer animations (1.8s, 60fps, GPU-accelerated)
- Click-to-select with visual feedback (green border, shadow, checkmark)
- Radio button behavior (only one selection at a time)
- Download button with enable/disable state management
- Keyboard navigation support (Tab, Enter, Space, ESC)
- Full ARIA attributes for screen reader accessibility
- Responsive layout (3 cols desktop, 2 cols tablet, 1 col mobile)
- Multilingual support (EN/ES) using Go template conditionals
- Download stub (shows alert, ready for backend integration)

Implementation:
- templates/partials/modals/pdf-modal.html: Complete rewrite (244 lines)
- static/css/main.css: Add PDF modal section (+290 lines)
- tests/mjs/14-pdf-modal.test.mjs: Comprehensive E2E test suite (570 lines)
- prompts/005-pdf-download-thumbnails-IMPLEMENTATION.md: Documentation

Tests:  12/12 PASSED
- Modal structure validation
- Three thumbnail cards display
- Selection interaction (click, keyboard)
- Download button state management
- ESC key closes modal
- Accessibility compliance (ARIA, roles, tabindex)
- Responsive layout (375px, 768px, 1920px)
- Multilingual support validation
- No console errors

Screenshots:
- tests/screenshots/pdf-modal-initial.png
- tests/screenshots/pdf-modal-short-selected.png
- tests/screenshots/pdf-modal-long-selected.png

Technical Details:
- Uses Hyperscript for state management (consistent with project)
- Native <dialog> element for accessibility
- Reuses skeleton.css patterns for shimmer animation
- Follows existing modal patterns (shortcuts-modal.html)
- Performance: <5KB gzipped overhead
- Browser support: 95%+ (all modern browsers)

Next Steps:
- Backend PDF generation (/download-pdf endpoint)
- Custom wizard implementation (Phase 3)
- PDF preview feature (Phase 4)

Refs: prompts/005-pdf-download-thumbnails.md
2025-11-18 20:25:49 +00:00
juanatsap a8d6805e27 feat: enhance shortcuts modal and complete logos-to-icons rename
This commit includes graphical keyboard icons integration, modal styling
improvements, and comprehensive "Logos" to "Icons" terminology update.

Changes:
- Add graphical keyboard icons using Iconify MDI (Tab, Ctrl, Cmd, Esc, etc.)
- Implement color scheme: black title, green subtitle/headers, blue kbd elements
- Add visual boxes with borders and shadows for section grouping
- Change modal from 3-column to 2-column grid layout (900px width)
- Fix critical bug: all 5 sections now render (was only showing 2)

Rename "Logos" to "Icons" across entire codebase:
- Go models: ToggleLogos → ToggleIcons, ShowLogos → ShowIcons
- Routes: /toggle/logos → /toggle/icons
- Templates: desktop-logo-toggle → desktop-icon-toggle, #logoToggle → #iconToggle
- JavaScript: logoToggles → iconToggles, sync logic updated
- CSS: .show-logos → .show-icons
- UI JSON: toggleLogos → toggleIcons
- Comments and labels updated

Technical details:
- Rebuilt Go binary to fix template rendering error
- Fixed JSON struct tag: json:"toggleLogos" → json:"toggleIcons"
- Updated kbd element styling for icon alignment (inline-flex)
- Added margin-bottom to subtitle (0.5rem)
- Grid now 2 columns for better 5-section layout

All 5 sections now render correctly:
1. Zoom Control
2. View Controls
3. Navigation
4. Actions
5. Browser Defaults
2025-11-15 18:42:35 +00:00
juanatsap 1f7757c848 good 2025-11-15 15:59:54 +00:00
juanatsap 06eb490950 more htmx 2025-11-14 21:38:09 +00:00
juanatsap fda034ca78 phase iv -ii 2025-11-12 19:13:52 +00:00
juanatsap d36b67d1f1 templating phase i 2025-11-12 18:26:18 +00:00