From 31dae9fa1929b22541e24f9ca6d44ac8824cbb2f Mon Sep 17 00:00:00 2001 From: juanatsap Date: Sun, 9 Nov 2025 13:43:29 +0000 Subject: [PATCH] Add collapsible sections, restructure menu, and refine sidebar layouts - Wrapped all CV sections and sidebar sections in
tags for collapsibility - Added Expand All/Collapse All menu options with CV Sections submenu - Implemented smooth CSS animations for section expansion/collapse using max-height transitions - Fixed menu item alignment issues (removed extra padding) - Added dash between company name and duration in experience section - Moved SAP Technologies and AI-Assisted Development to bottom of right sidebar - Reordered JavaScript Ecosystem above Go Ecosystem in left sidebar - Implemented different layouts for left vs right sidebars: - Left sidebar: title left-aligned, triangle on right - Right sidebar: title right-aligned, triangle on left - Adjusted sidebar spacing for better visual hierarchy when sections are open/closed --- data/cv-en.json | 62 +++++------ data/cv-es.json | 62 +++++------ static/css/main.css | 213 +++++++++++++++++++++++++++++++++++++- templates/cv-content.html | 134 ++++++++++++++++-------- templates/index.html | 110 ++++++++++++++------ 5 files changed, 439 insertions(+), 142 deletions(-) diff --git a/data/cv-en.json b/data/cv-en.json index 4a3c2eb..2b84448 100644 --- a/data/cv-en.json +++ b/data/cv-en.json @@ -212,7 +212,7 @@ { "position": "Programmer Analyst (Freelance)", "company": "TwenTiC + ALTEN", - "companyURL": "https://www.twentic.com/kit-digital/", + "companyURL": "https://www.twentic.com/", "location": "Barcelona, Spain", "startDate": "2012-05", "endDate": "2012-10", @@ -327,24 +327,16 @@ ] }, { - "category": "SAP Technologies", + "category": "JavaScript Ecosystem", "proficiency": 5, + "sidebar": "left", "items": [ - "SAP Customer Data Cloud (CDC)", - "SAP Cloud Platform", - "SAP S/4HANA", - "GDPR Compliance & Data Protection" - ] - }, - { - "category": "AI-Assisted Development", - "proficiency": 5, - "items": [ - "AI Development Workflows (Claude Code, Copilot, GPT-4)", - "Agent-Based & Spec-Driven Development", - "Prompt Engineering & AI Integration", - "Automated Code Generation & Documentation", - "OpenAI & Anthropic APIs" + "Node.js & Express", + "React & React Ecosystem", + "Redux/Flux", + "Modern Build Tools (Webpack, Vite, ESBuild)", + "Package Management (npm, pnpm, bun)", + "Testing Frameworks (Jest, Playwright)" ] }, { @@ -361,19 +353,6 @@ "Standard Library (net/http, html/template)" ] }, - { - "category": "JavaScript Ecosystem", - "proficiency": 5, - "sidebar": "left", - "items": [ - "Node.js & Express", - "React & React Ecosystem", - "Redux/Flux", - "Modern Build Tools (Webpack, Vite, ESBuild)", - "Package Management (npm, pnpm, bun)", - "Testing Frameworks (Jest, Playwright)" - ] - }, { "category": "Frontend Technologies", "proficiency": 5, @@ -476,6 +455,29 @@ "Excalidraw", "GIMP" ] + }, + { + "category": "SAP Technologies", + "proficiency": 5, + "sidebar": "right", + "items": [ + "SAP Customer Data Cloud (CDC)", + "SAP Cloud Platform", + "SAP S/4HANA", + "GDPR Compliance & Data Protection" + ] + }, + { + "category": "AI-Assisted Development", + "proficiency": 5, + "sidebar": "right", + "items": [ + "AI Development Workflows (Claude Code, Copilot, GPT-4)", + "Agent-Based & Spec-Driven Development", + "Prompt Engineering & AI Integration", + "Automated Code Generation & Documentation", + "OpenAI & Anthropic APIs" + ] } ], "soft_skills": [ diff --git a/data/cv-es.json b/data/cv-es.json index 7c9c28e..2025a26 100644 --- a/data/cv-es.json +++ b/data/cv-es.json @@ -212,7 +212,7 @@ { "position": "Analista Programador (Freelance)", "company": "TwenTiC + ALTEN", - "companyURL": "https://www.twentic.com/kit-digital/", + "companyURL": "https://www.twentic.com/", "location": "Barcelona, España", "startDate": "2012-05", "endDate": "2012-10", @@ -327,24 +327,16 @@ ] }, { - "category": "Tecnologías SAP", + "category": "Ecosistema JavaScript", "proficiency": 5, + "sidebar": "left", "items": [ - "SAP Customer Data Cloud (CDC)", - "SAP Cloud Platform", - "SAP S/4HANA", - "Cumplimiento GDPR y Protección de Datos" - ] - }, - { - "category": "Desarrollo Asistido por IA", - "proficiency": 5, - "items": [ - "Flujos de Desarrollo con IA (Claude Code, Copilot, GPT-4)", - "Desarrollo Basado en Agentes y Especificaciones", - "Ingeniería de Prompts e Integración de IA", - "Generación Automática de Código y Documentación", - "APIs OpenAI y Anthropic" + "Node.js y Express", + "React y Ecosistema React", + "Redux/Flux", + "Herramientas de Build Modernas (Webpack, Vite, ESBuild)", + "Gestión de Paquetes (npm, pnpm, bun)", + "Frameworks de Testing (Jest, Playwright)" ] }, { @@ -361,19 +353,6 @@ "Biblioteca Estándar (net/http, html/template)" ] }, - { - "category": "Ecosistema JavaScript", - "proficiency": 5, - "sidebar": "left", - "items": [ - "Node.js y Express", - "React y Ecosistema React", - "Redux/Flux", - "Herramientas de Build Modernas (Webpack, Vite, ESBuild)", - "Gestión de Paquetes (npm, pnpm, bun)", - "Frameworks de Testing (Jest, Playwright)" - ] - }, { "category": "Tecnologías Frontend", "proficiency": 5, @@ -476,6 +455,29 @@ "Excalidraw", "GIMP" ] + }, + { + "category": "Tecnologías SAP", + "proficiency": 5, + "sidebar": "right", + "items": [ + "SAP Customer Data Cloud (CDC)", + "SAP Cloud Platform", + "SAP S/4HANA", + "Cumplimiento GDPR y Protección de Datos" + ] + }, + { + "category": "Desarrollo Asistido por IA", + "proficiency": 5, + "sidebar": "right", + "items": [ + "Flujos de Desarrollo con IA (Claude Code, Copilot, GPT-4)", + "Desarrollo Basado en Agentes y Especificaciones", + "Ingeniería de Prompts e Integración de IA", + "Generación Automática de Código y Documentación", + "APIs OpenAI y Anthropic" + ] } ], "soft_skills": [ diff --git a/static/css/main.css b/static/css/main.css index 7405210..ffec80e 100644 --- a/static/css/main.css +++ b/static/css/main.css @@ -522,7 +522,7 @@ iconify-icon { /* Sidebar - Left column */ .cv-sidebar { background: var(--sidebar-gray); - padding: 2rem 1.5rem; + padding: 4rem 1.5rem; font-size: 0.9rem; } @@ -530,6 +530,12 @@ iconify-icon { margin-bottom: 2rem; } +/* Add margin when sidebar section is collapsed */ +.sidebar-section:has(details:not([open])) { + margin-bottom: 3rem; + margin-top: 0rem; +} + .sidebar-title { font-family: 'Quicksand', sans-serif; font-size: 1.4em; @@ -540,6 +546,96 @@ iconify-icon { color: rgb(51, 51, 51); } +/* Collapsible Sidebar Section Styles */ +.sidebar-section details { + margin: 0; +} + +.sidebar-section details summary ~ * { + overflow: hidden; + max-height: 0; + opacity: 0; + transform: translateY(-8px); + transition: max-height 0.5s ease-in-out, + opacity 0.3s ease-in-out, + transform 0.3s ease-in-out; +} + +.sidebar-section details[open] summary ~ * { + max-height: 1500px; + opacity: 1; + transform: translateY(0); +} + +.sidebar-section summary { + cursor: pointer; + list-style: none; + user-select: none; + position: relative; + display: flex; + align-items: center; + justify-content: space-between; +} + +/* Remove default triangle marker */ +.sidebar-section summary::-webkit-details-marker, +.sidebar-section summary::marker { + display: none; +} + +/* Sidebar title - no special positioning */ +.sidebar-section summary .sidebar-title { + margin-bottom: 0; +} + +/* Add custom collapse indicator at the far right (left sidebar) */ +.cv-sidebar-left .sidebar-section summary::after { + content: '▶'; + font-size: 0.8em; + color: rgb(100, 100, 100); + transition: transform 0.2s ease, opacity 0.2s ease; + opacity: 0; + margin-left: 15px; + flex-shrink: 0; +} + +/* Add custom collapse indicator at the far left (right sidebar) */ +.cv-sidebar-right .sidebar-section summary { + flex-direction: row-reverse; + justify-content: space-between; +} + +.cv-sidebar-right .sidebar-section summary .sidebar-title { + text-align: right; + width: 100%; +} + +.cv-sidebar-right .sidebar-section summary::after { + content: '▶'; + font-size: 0.8em; + color: rgb(100, 100, 100); + transition: transform 0.2s ease, opacity 0.2s ease; + opacity: 0; + margin-right: 15px; + flex-shrink: 0; +} + +/* Show indicator on hover or when closed */ +.sidebar-section summary:hover::after, +.sidebar-section details:not([open]) summary::after { + opacity: 1; +} + +/* Rotate indicator when open */ +.sidebar-section details[open] summary::after { + transform: rotate(90deg); +} + +/* Hover effect on sidebar summary */ +.sidebar-section summary:hover .sidebar-title { + color: var(--accent-blue); +} + .sidebar-content { font-family: 'Quicksand', sans-serif; font-size: 0.95em; @@ -547,6 +643,11 @@ iconify-icon { line-height: 1.5; } +/* Add breathing space when sidebar section is open */ +.sidebar-section details[open] .sidebar-content { + margin-top: 0.5rem; +} + .skill-item { margin-bottom: 0.15rem; color: rgb(0, 0, 0); @@ -672,6 +773,11 @@ iconify-icon { page-break-inside: avoid; } +/* Remove margin when section is collapsed */ +.cv-section:has(details:not([open])) { + margin-bottom: 0; +} + .section-title { font-family: 'Quicksand', sans-serif; font-size: 1.4em; @@ -682,6 +788,72 @@ iconify-icon { color: rgb(51, 51, 51); } +/* Collapsible Section Styles */ +.cv-section details { + margin: 0; +} + +.cv-section details summary ~ * { + overflow: hidden; + max-height: 0; + opacity: 0; + transform: translateY(-8px); + transition: max-height 0.5s ease-in-out, + opacity 0.3s ease-in-out, + transform 0.3s ease-in-out; +} + +.cv-section details[open] summary ~ * { + max-height: 3000px; + opacity: 1; + transform: translateY(0); +} + +.cv-section summary { + cursor: pointer; + list-style: none; + user-select: none; + position: relative; +} + +/* Remove default triangle marker in all browsers */ +.cv-section summary::-webkit-details-marker, +.cv-section summary::marker { + display: none; +} + +/* Add custom collapse indicator after the title */ +.cv-section summary .section-title { + display: inline-flex; + align-items: center; + gap: 0.5rem; +} + +.cv-section summary .section-title::after { + content: '▼'; + font-size: 0.8em; + color: rgb(100, 100, 100); + transition: transform 0.2s ease, opacity 0.2s ease; + opacity: 0; + margin-left: 0.5rem; +} + +/* Show indicator on hover or when closed */ +.cv-section summary:hover .section-title::after, +.cv-section details:not([open]) summary .section-title::after { + opacity: 1; +} + +/* Rotate indicator when closed */ +.cv-section details:not([open]) summary .section-title::after { + transform: rotate(-90deg); +} + +/* Hover effect on summary */ +.cv-section summary:hover .section-title { + color: var(--accent-blue); +} + .summary-text { font-family: 'Quicksand', sans-serif; line-height: 1.5; @@ -780,8 +952,8 @@ iconify-icon { } .duration-text { - color: #999; - font-weight: normal; + color: #aaa; + font-weight: 500; } .responsibilities { @@ -1884,6 +2056,41 @@ a:focus { color: var(--accent-blue); } +/* Remove extra padding - all menu items should align consistently */ + +/* Submenu styles */ +.menu-item-submenu { + position: relative; +} + +.menu-item.has-submenu { + justify-content: space-between; + position: relative; +} + +.submenu-arrow { + transition: transform 0.2s ease; +} + +.menu-item-submenu.submenu-open .submenu-arrow { + transform: rotate(180deg); +} + +.submenu-content { + display: none; + background-color: rgba(0, 0, 0, 0.02); +} + +.menu-item-submenu.submenu-open .submenu-content { + display: block; +} + +.submenu-content .menu-item { + padding-left: 3rem; + font-size: 0.9rem; + border-left-width: 2px; +} + /* Section icons in titles */ .section-icon { vertical-align: middle; diff --git a/templates/cv-content.html b/templates/cv-content.html index 68ca334..7d4fdd8 100644 --- a/templates/cv-content.html +++ b/templates/cv-content.html @@ -21,10 +21,14 @@ @@ -48,23 +52,30 @@
-

- - {{if eq .Lang "es"}}Formación{{else}}Training{{end}} -

+
+ +

+ + {{if eq .Lang "es"}}Formación{{else}}Training{{end}} +

+
{{range .CV.Education}}
{{.Degree}} ({{.StartDate}}-{{.EndDate}}) {{if eq $.Lang "es"}}obtenido de{{else}}obtained from the{{end}} {{.Institution}} ({{.Location}})
{{end}} +
-

- - {{if eq .Lang "es"}}Competencias{{else}}Skills{{end}} -

+
+ +

+ + {{if eq .Lang "es"}}Competencias{{else}}Skills{{end}} +

+

{{if eq .Lang "es"}} Amplio conocimiento en entornos web, tanto J2EE como PHP. Experto en tecnologías front-end, aunque con considerable experiencia en sistemas back-end. Receptivo al aprendizaje de nuevas tecnologías, y con una gran dosis de creatividad. Capacidad de analizar problemas y aportar soluciones específicas adaptadas a cada tipo de cliente. Me gusta trabajar tanto solo como en grupos. @@ -72,14 +83,18 @@ Extensive knowledge in web environments, both J2EE and PHP. Expert in front-end technologies, although with considerable experience in back-end systems. Receptive to learning new technologies, and with a large dose of creativity. Ability to analyze problems and provide specific solutions tailored to each client type. I like to work both alone and in groups. {{end}}

+
-

- - {{if eq .Lang "es"}}Experiencia{{else}}Experience{{end}} -

+
+ +

+ + {{if eq .Lang "es"}}Experiencia{{else}}Experience{{end}} +

+
{{range .CV.Experience}}
@@ -91,7 +106,7 @@ {{end}}
- {{.Position}}{{if .Company}} - {{if .CompanyURL}}{{.Company}}{{else}}{{.Company}}{{end}}{{if .Duration}} {{.Duration}}{{end}}{{end}}
+ {{.Position}}{{if .Company}} - {{if .CompanyURL}}{{.Company}}{{else}}{{.Company}}{{end}}{{if .Duration}} - {{.Duration}}{{end}}{{end}}
{{.StartDate}} / {{if .Current}}{{if eq $.Lang "es"}}presente{{else}}now{{end}}{{else}}{{.EndDate}}{{end}} - ({{.Location}}) {{if .ShortDescription}} @@ -108,6 +123,7 @@
{{end}} +
@@ -135,10 +151,13 @@ {{if .CV.Awards}}
-

- - {{if eq .Lang "es"}}Premios y Reconocimientos{{else}}Awards{{end}} -

+
+ +

+ + {{if eq .Lang "es"}}Premios y Reconocimientos{{else}}Awards{{end}} +

+
{{range .CV.Awards}}
{{if .AwardLogo}} @@ -164,16 +183,20 @@
{{end}} +
{{end}} {{if .CV.Projects}}
-

- - {{if eq .Lang "es"}}Proyectos Personales / Freelance{{else}}Personal / Freelance Projects{{end}} -

+
+ +

+ + {{if eq .Lang "es"}}Proyectos Personales / Freelance{{else}}Personal / Freelance Projects{{end}} +

+
{{range .CV.Projects}}
{{if .ProjectLogo}} @@ -222,16 +245,20 @@

{{if eq .Lang "es"}}Ver todos los proyectos en mi{{else}}See all projects on my{{end}} {{if eq .Lang "es"}}portfolio de Domestika{{else}}Domestika portfolio{{end}}

+
{{end}} {{if .CV.Courses}}
-

- - {{if eq .Lang "es"}}Cursos Realizados{{else}}Courses{{end}} -

+
+ +

+ + {{if eq .Lang "es"}}Cursos Realizados{{else}}Courses{{end}} +

+
{{range .CV.Courses}}
{{if .CourseLogo}} @@ -261,47 +288,60 @@
{{end}} +
{{end}}
-

- - {{if eq .Lang "es"}}Idiomas{{else}}Languages{{end}} -

+
+ +

+ + {{if eq .Lang "es"}}Idiomas{{else}}Languages{{end}} +

+
{{range .CV.Languages}}
{{.Language}}: {{.Proficiency}}{{if .Detail}} {{.Detail}}{{end}}
{{end}} +
{{if .CV.References}}
-

- - {{if eq .Lang "es"}}Referencias{{else}}References{{end}} -

+
+ +

+ + {{if eq .Lang "es"}}Referencias{{else}}References{{end}} +

+
{{range .CV.References}}
{{if .TextBefore}}{{.TextBefore}} {{end}}{{if .LinkText}}{{.LinkText}}{{else}}{{.Title}}{{end}}{{if .TextAfter}} {{.TextAfter}}{{end}}
{{end}} +
{{end}} {{if .CV.Other.DriverLicense}}
-

- - {{if eq .Lang "es"}}Otros{{else}}Other{{end}} -

+
+ +

+ + {{if eq .Lang "es"}}Otros{{else}}Other{{end}} +

+
{{if eq .Lang "es"}}Carnet de conducir tipo {{.CV.Other.DriverLicense | safeHTML}}{{else}}Driving License type {{.CV.Other.DriverLicense | safeHTML}}{{end}}
+
{{end}} @@ -310,10 +350,14 @@ diff --git a/templates/index.html b/templates/index.html index 70f687a..355eb14 100644 --- a/templates/index.html +++ b/templates/index.html @@ -189,42 +189,59 @@ @@ -280,6 +297,31 @@ // Flag to keep header visible after navigation let keepHeaderVisible = false; + // Expand all sections + function expandAllSections(event) { + event.preventDefault(); + const allDetails = document.querySelectorAll('details'); + allDetails.forEach(detail => { + detail.setAttribute('open', ''); + }); + } + + // Collapse all sections + function collapseAllSections(event) { + event.preventDefault(); + const allDetails = document.querySelectorAll('details'); + allDetails.forEach(detail => { + detail.removeAttribute('open'); + }); + } + + // Toggle submenu + function toggleSubmenu(event) { + event.preventDefault(); + const submenuContainer = event.currentTarget.parentElement; + submenuContainer.classList.toggle('submenu-open'); + } + // Scroll to section smoothly function scrollToSection(sectionId) { event.preventDefault(); // Prevent default anchor behavior