Add collapsible sections, restructure menu, and refine sidebar layouts

- Wrapped all CV sections and sidebar sections in <details> 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
This commit is contained in:
juanatsap
2025-11-09 13:43:29 +00:00
parent 2ce13481d0
commit 31dae9fa19
5 changed files with 439 additions and 142 deletions
+32 -30
View File
@@ -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": [
+32 -30
View File
@@ -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": [
+210 -3
View File
@@ -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;
+45 -1
View File
@@ -21,10 +21,14 @@
<aside class="cv-sidebar cv-sidebar-left">
{{range $index, $category := .SkillsLeft}}
<section class="sidebar-section">
<details open>
<summary>
<h3 class="sidebar-title">{{$category.Category}}</h3>
</summary>
<div class="sidebar-content">
{{range $category.Items}}<div class="skill-item">{{.}}</div>{{end}}
</div>
</details>
</section>
{{end}}
</aside>
@@ -48,23 +52,30 @@
<!-- Education -->
<section id="education" class="cv-section">
<details open>
<summary>
<h3 class="section-title">
<iconify-icon icon="mdi:school" width="24" height="24" class="section-icon"></iconify-icon>
{{if eq .Lang "es"}}Formación{{else}}Training{{end}}
</h3>
</summary>
{{range .CV.Education}}
<div class="education-item">
<strong>{{.Degree}}</strong> ({{.StartDate}}-{{.EndDate}}) {{if eq $.Lang "es"}}obtenido de{{else}}obtained from the{{end}} <strong>{{.Institution}}</strong> ({{.Location}})
</div>
{{end}}
</details>
</section>
<!-- Skills Summary -->
<section id="skills" class="cv-section">
<details open>
<summary>
<h3 class="section-title">
<iconify-icon icon="mdi:brain" width="24" height="24" class="section-icon"></iconify-icon>
{{if eq .Lang "es"}}Competencias{{else}}Skills{{end}}
</h3>
</summary>
<p class="summary-text">
{{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}}
</p>
</details>
</section>
<!-- Experience -->
<section id="experience" class="cv-section">
<details open>
<summary>
<h3 class="section-title">
<iconify-icon icon="mdi:office-building" width="24" height="24" class="section-icon"></iconify-icon>
{{if eq .Lang "es"}}Experiencia{{else}}Experience{{end}}
</h3>
</summary>
{{range .CV.Experience}}
<div class="experience-item">
@@ -91,7 +106,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}}{{if .Duration}} <span class="duration-text">{{.Duration}}</span>{{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}}
@@ -108,6 +123,7 @@
</div>
</div>
{{end}}
</details>
</section>
</main>
</div>
@@ -135,10 +151,13 @@
<!-- Awards Section -->
{{if .CV.Awards}}
<section id="awards" class="cv-section">
<details open>
<summary>
<h3 class="section-title">
<iconify-icon icon="mdi:trophy" width="24" height="24" class="section-icon"></iconify-icon>
{{if eq .Lang "es"}}Premios y Reconocimientos{{else}}Awards{{end}}
</h3>
</summary>
{{range .CV.Awards}}
<div class="award-item">
{{if .AwardLogo}}
@@ -164,16 +183,20 @@
</div>
</div>
{{end}}
</details>
</section>
{{end}}
<!-- Projects Section -->
{{if .CV.Projects}}
<section id="projects" class="cv-section">
<details open>
<summary>
<h3 class="section-title">
<iconify-icon icon="mdi:web" width="24" height="24" class="section-icon"></iconify-icon>
{{if eq .Lang "es"}}Proyectos Personales / Freelance{{else}}Personal / Freelance Projects{{end}}
</h3>
</summary>
{{range .CV.Projects}}
<div class="project-item">
{{if .ProjectLogo}}
@@ -222,16 +245,20 @@
<p>{{if eq .Lang "es"}}Ver todos los proyectos en mi{{else}}See all projects on my{{end}}
<a href="{{.CV.Personal.Domestika}}" target="_blank" rel="noopener noreferrer"><strong>{{if eq .Lang "es"}}portfolio de Domestika{{else}}Domestika portfolio{{end}}</strong></a></p>
</div>
</details>
</section>
{{end}}
<!-- Courses Section -->
{{if .CV.Courses}}
<section id="courses" class="cv-section">
<details open>
<summary>
<h3 class="section-title">
<iconify-icon icon="mdi:school" width="24" height="24" class="section-icon"></iconify-icon>
{{if eq .Lang "es"}}Cursos Realizados{{else}}Courses{{end}}
</h3>
</summary>
{{range .CV.Courses}}
<div class="course-item">
{{if .CourseLogo}}
@@ -261,47 +288,60 @@
</div>
</div>
{{end}}
</details>
</section>
{{end}}
<!-- Languages Section -->
<section id="languages" class="cv-section">
<details open>
<summary>
<h3 class="section-title">
<iconify-icon icon="mdi:translate" width="24" height="24" class="section-icon"></iconify-icon>
{{if eq .Lang "es"}}Idiomas{{else}}Languages{{end}}
</h3>
</summary>
{{range .CV.Languages}}
<div class="language-item">
<strong>{{.Language}}:</strong> {{.Proficiency}}{{if .Detail}} {{.Detail}}{{end}}
</div>
{{end}}
</details>
</section>
<!-- References Section -->
{{if .CV.References}}
<section id="references" class="cv-section">
<details open>
<summary>
<h3 class="section-title">
<iconify-icon icon="mdi:link-variant" width="24" height="24" class="section-icon"></iconify-icon>
{{if eq .Lang "es"}}Referencias{{else}}References{{end}}
</h3>
</summary>
{{range .CV.References}}
<div class="reference-item">
{{if .TextBefore}}{{.TextBefore}} {{end}}<a href="{{.URL}}" target="_blank" rel="noopener noreferrer"><strong>{{if .LinkText}}{{.LinkText}}{{else}}{{.Title}}{{end}}</strong></a>{{if .TextAfter}} {{.TextAfter}}{{end}}
</div>
{{end}}
</details>
</section>
{{end}}
<!-- Other Section (Driver's License) -->
{{if .CV.Other.DriverLicense}}
<section id="other" class="cv-section">
<details open>
<summary>
<h3 class="section-title">
<iconify-icon icon="mdi:information" width="24" height="24" class="section-icon"></iconify-icon>
{{if eq .Lang "es"}}Otros{{else}}Other{{end}}
</h3>
</summary>
<div class="other-content">
{{if eq .Lang "es"}}Carnet de conducir tipo {{.CV.Other.DriverLicense | safeHTML}}{{else}}Driving License type {{.CV.Other.DriverLicense | safeHTML}}{{end}}
</div>
</details>
</section>
{{end}}
</main>
@@ -310,10 +350,14 @@
<aside class="cv-sidebar cv-sidebar-right">
{{range $index, $category := .SkillsRight}}
<section class="sidebar-section">
<details open>
<summary>
<h3 class="sidebar-title">{{$category.Category}}</h3>
</summary>
<div class="sidebar-content">
{{range $category.Items}}<div class="skill-item">{{.}}</div>{{end}}
</div>
</details>
</section>
{{end}}
</aside>
+42
View File
@@ -189,6 +189,21 @@
<!-- Navigation Menu (Hidden by default) -->
<nav id="navigation-menu" class="navigation-menu no-print" role="navigation" aria-label="CV sections">
<div class="menu-content">
<a href="#" class="menu-item" onclick="expandAllSections(event)">
<iconify-icon icon="mdi:arrow-expand-all" width="20" height="20"></iconify-icon>
<span>{{if eq .Lang "es"}}Expandir Todo{{else}}Expand All{{end}}</span>
</a>
<a href="#" class="menu-item" onclick="collapseAllSections(event)">
<iconify-icon icon="mdi:arrow-collapse-all" width="20" height="20"></iconify-icon>
<span>{{if eq .Lang "es"}}Colapsar Todo{{else}}Collapse All{{end}}</span>
</a>
<div class="menu-item-submenu">
<a href="#" class="menu-item has-submenu" onclick="toggleSubmenu(event)">
<iconify-icon icon="mdi:menu" width="20" height="20"></iconify-icon>
<span>{{if eq .Lang "es"}}Secciones CV{{else}}CV Sections{{end}}</span>
<iconify-icon icon="mdi:chevron-down" width="16" height="16" class="submenu-arrow"></iconify-icon>
</a>
<div class="submenu-content">
<a href="#education" class="menu-item" onclick="scrollToSection('education')">
<iconify-icon icon="mdi:school" width="20" height="20"></iconify-icon>
<span>{{if eq .Lang "es"}}Formación{{else}}Training{{end}}</span>
@@ -226,6 +241,8 @@
<span>{{if eq .Lang "es"}}Otros{{else}}Other{{end}}</span>
</a>
</div>
</div>
</div>
</nav>
<!-- CV Content Container -->
@@ -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