diff --git a/ADDING-YOUR-PHOTO.md b/ADDING-YOUR-PHOTO.md
new file mode 100644
index 0000000..0552177
--- /dev/null
+++ b/ADDING-YOUR-PHOTO.md
@@ -0,0 +1,72 @@
+# Cómo Añadir tu Foto al CV
+
+## 📸 Paso 1: Prepara tu Foto
+
+1. **Busca una foto profesional** (preferiblemente tipo LinkedIn)
+2. **Formato recomendado**: JPG o PNG
+3. **Tamaño**: Al menos 300x300 píxeles (cuadrada es mejor)
+4. **Calidad**: Fondo neutro, buena iluminación
+
+## 📁 Paso 2: Guarda la Foto
+
+Guarda tu foto en:
+```
+static/images/profile/photo.jpg
+```
+
+Puedes usar cualquiera de estos nombres:
+- `photo.jpg` ✅ (recomendado)
+- `photo.png` (cambiar en template)
+- `profile.jpg` (cambiar en template)
+
+## 🔄 Paso 3: Actualizar (si usas otro nombre)
+
+Si tu foto se llama diferente a `photo.jpg`, edita `templates/cv-content.html`:
+
+```html
+
+
+
+
+
+```
+
+## 🖼️ Descargar desde LinkedIn
+
+### Opción 1: Manualmente
+1. Abre tu perfil de LinkedIn
+2. Click derecho en tu foto → "Guardar imagen como..."
+3. Guárdala como `photo.jpg` en `static/images/profile/`
+
+### Opción 2: Desde tu sitio actual
+Si ya tienes tu foto en https://juan.andres.morenoyrubio.com:
+
+```bash
+cd static/images/profile
+# Abre el inspector del navegador, busca tu foto, y copia la URL
+curl -o photo.jpg "URL_DE_TU_FOTO"
+```
+
+## ✅ Verificar
+
+1. Reinicia el servidor: `./cv-server`
+2. Abre http://localhost:8080
+3. Deberías ver tu foto en la esquina superior izquierda
+
+Si no funciona, verás un placeholder gris con el texto "Add your photo".
+
+## 🎨 Ajustar el Tamaño (Opcional)
+
+La foto se muestra como un círculo de 120px. Para cambiar el tamaño, edita `static/css/main.css`:
+
+```css
+.cv-photo {
+ width: 150px; /* Cambiar aquí */
+ height: 150px; /* Y aquí */
+ border-radius: 50%;
+}
+```
+
+---
+
+**Nota**: El template ya incluye un fallback automático al placeholder si la foto no existe, así que el sitio funcionará con o sin foto.
diff --git a/data/cv-en.json b/data/cv-en.json
index ab9a73e..00434af 100644
--- a/data/cv-en.json
+++ b/data/cv-en.json
@@ -35,7 +35,9 @@
"React",
"Node.js",
"API Integration"
- ]
+ ],
+ "companyLogo": "olympic-broadcasting.png",
+ "shortDescription": "SAP CDC solutions for international broadcasting events. Custom implementations and technical guidance."
},
{
"position": "Senior Technical Consultant",
@@ -64,7 +66,9 @@
"highlights": [
"Successfully deployed authentication system for all AENA airports in Spain",
"Managed identity flows for millions of users across web and mobile platforms"
- ]
+ ],
+ "companyLogo": "aena.png",
+ "shortDescription": "Lead Technical Consultant for AENA Airports Authentication System serving millions of passengers across all Spanish airports."
},
{
"position": "Senior Technical Consultant",
@@ -87,7 +91,9 @@
"JavaScript",
"Cloud Platforms",
"Technical Documentation"
- ]
+ ],
+ "companyLogo": "sap.png",
+ "shortDescription": "SAP Customer Data Cloud technical consulting, troubleshooting, and stakeholder education on GDPR compliance."
},
{
"position": "Junior Technical Consultant",
@@ -109,7 +115,9 @@
"JavaScript",
"Customer Support",
"System Monitoring"
- ]
+ ],
+ "companyLogo": "gigya.png",
+ "shortDescription": "Technical support and problem-solving for Gigya platform. System monitoring and training program development."
},
{
"position": "Fullstack Developer",
@@ -130,7 +138,9 @@
"Video Processing",
"Database Design",
"PostgreSQL"
- ]
+ ],
+ "companyLogo": "megabanner.png",
+ "shortDescription": "Full-stack development with video system integration for advertisement inclusion in gas station networks."
},
{
"position": "Fullstack Developer",
@@ -152,7 +162,9 @@
"API Design",
"CI/CD",
"DevOps"
- ]
+ ],
+ "companyLogo": "everis.png",
+ "shortDescription": "API design and automated deployment pipelines. Software testing and scalability implementation."
},
{
"position": "FullStack Developer",
@@ -170,7 +182,9 @@
"JavaScript",
"Redux",
"Webpack"
- ]
+ ],
+ "companyLogo": "everis.png",
+ "shortDescription": "React application development for multiple clients."
},
{
"position": "Fullstack Developer",
@@ -187,7 +201,9 @@
"Java",
"JavaScript",
"Web Development"
- ]
+ ],
+ "companyLogo": "indra.png",
+ "shortDescription": "Project management and customer feedback collection across development stages."
},
{
"position": "Technical Director / Programmer",
@@ -212,7 +228,8 @@
"highlights": [
"Reduced production times by 75% through optimized pipelines",
"Successfully managed technical team and product development"
- ]
+ ],
+ "shortDescription": "Technical Director leading development of backend and 5 websites. Reduced production times by 75%."
},
{
"position": "Programmer Analyst (Freelance)",
@@ -230,7 +247,8 @@
"PHP",
"MySQL",
"JavaScript"
- ]
+ ],
+ "shortDescription": "WordPress and PHP website development as freelance programmer."
},
{
"position": "Analyst Programmer / Expert Technician",
@@ -248,7 +266,8 @@
"Java",
"System Configuration",
"Technical Support"
- ]
+ ],
+ "shortDescription": "Software and hardware configuration, technical problem-solving, and team mentoring."
},
{
"position": "Senior Programmer",
@@ -266,7 +285,8 @@
"Java",
"Search Engine Technology",
"European R&D Projects"
- ]
+ ],
+ "shortDescription": "European R&D project for revolutionary search engine development."
},
{
"position": "Junior Programmer",
@@ -285,7 +305,8 @@
"Java Applets",
"Data Visualization",
"Chart Generation"
- ]
+ ],
+ "shortDescription": "JAVA development specialized in data chart generation and applet development."
}
],
"education": [
diff --git a/data/cv-es.json b/data/cv-es.json
index fe8f47a..620949d 100644
--- a/data/cv-es.json
+++ b/data/cv-es.json
@@ -35,7 +35,9 @@
"React",
"Node.js",
"Integración de APIs"
- ]
+ ],
+ "companyLogo": "olympic-broadcasting.png",
+ "shortDescription": "Soluciones SAP CDC para eventos de transmisión internacional. Implementaciones personalizadas y orientación técnica."
},
{
"position": "Consultor Técnico Senior",
@@ -64,7 +66,9 @@
"highlights": [
"Despliegue exitoso del sistema de autenticación para todos los aeropuertos AENA en España",
"Gestión de flujos de identidad para millones de usuarios en plataformas web y móviles"
- ]
+ ],
+ "companyLogo": "aena.png",
+ "shortDescription": "Consultor Técnico Principal del Sistema de Autenticación de Aeropuertos AENA sirviendo a millones de pasajeros en todos los aeropuertos españoles."
},
{
"position": "Consultor Técnico Senior",
@@ -87,7 +91,9 @@
"JavaScript",
"Plataformas Cloud",
"Documentación Técnica"
- ]
+ ],
+ "companyLogo": "sap.png",
+ "shortDescription": "Consultoría técnica SAP Customer Data Cloud, resolución de problemas y educación de stakeholders en cumplimiento GDPR."
},
{
"position": "Consultor Técnico Junior",
@@ -109,7 +115,9 @@
"JavaScript",
"Soporte al Cliente",
"Monitoreo de Sistemas"
- ]
+ ],
+ "companyLogo": "gigya.png",
+ "shortDescription": "Soporte técnico y resolución de problemas para plataforma Gigya. Monitoreo de sistemas y desarrollo de programas de formación."
},
{
"position": "Desarrollador Fullstack",
@@ -130,7 +138,9 @@
"Procesamiento de Video",
"Diseño de Bases de Datos",
"PostgreSQL"
- ]
+ ],
+ "companyLogo": "megabanner.png",
+ "shortDescription": "Desarrollo full-stack con integración de sistema de video para inclusión de anuncios en redes de estaciones de servicio."
},
{
"position": "Desarrollador Fullstack",
@@ -152,7 +162,9 @@
"Diseño de APIs",
"CI/CD",
"DevOps"
- ]
+ ],
+ "companyLogo": "everis.png",
+ "shortDescription": "Diseño de APIs y pipelines de despliegue automatizados. Testing de software e implementación de escalabilidad."
},
{
"position": "Desarrollador FullStack",
@@ -170,7 +182,9 @@
"JavaScript",
"Redux",
"Webpack"
- ]
+ ],
+ "companyLogo": "everis.png",
+ "shortDescription": "Desarrollo de aplicaciones React para múltiples clientes."
},
{
"position": "Desarrollador Fullstack",
@@ -187,7 +201,9 @@
"Java",
"JavaScript",
"Desarrollo Web"
- ]
+ ],
+ "companyLogo": "indra.png",
+ "shortDescription": "Gestión de proyectos y recopilación de feedback de clientes en diferentes etapas de desarrollo."
},
{
"position": "Director Técnico / Programador",
@@ -212,7 +228,8 @@
"highlights": [
"Reducción del 75% en tiempos de producción mediante pipelines optimizados",
"Gestión exitosa de equipo técnico y desarrollo de productos"
- ]
+ ],
+ "shortDescription": "Director Técnico liderando desarrollo de backend y 5 sitios web. Reducción del 75% en tiempos de producción."
},
{
"position": "Analista Programador (Freelance)",
@@ -230,7 +247,8 @@
"PHP",
"MySQL",
"JavaScript"
- ]
+ ],
+ "shortDescription": "Desarrollo de sitios web WordPress y PHP como programador freelance."
},
{
"position": "Analista Programador / Técnico Experto",
@@ -248,7 +266,8 @@
"Java",
"Configuración de Sistemas",
"Soporte Técnico"
- ]
+ ],
+ "shortDescription": "Configuración de software y hardware, resolución de problemas técnicos y mentoría de equipos."
},
{
"position": "Programador Senior",
@@ -266,7 +285,8 @@
"Java",
"Tecnología de Motores de Búsqueda",
"Proyectos Europeos I+D"
- ]
+ ],
+ "shortDescription": "Proyecto europeo I+D para desarrollo de motor de búsqueda revolucionario."
},
{
"position": "Programador Junior",
@@ -285,7 +305,8 @@
"Applets Java",
"Visualización de Datos",
"Generación de Gráficos"
- ]
+ ],
+ "shortDescription": "Desarrollo JAVA especializado en generación de gráficos de datos y desarrollo de applets."
}
],
"education": [
diff --git a/download-logos.sh b/download-logos.sh
new file mode 100755
index 0000000..fbd0906
--- /dev/null
+++ b/download-logos.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+# Download company logos
+cd static/images/companies
+
+# Olympic Broadcasting Services
+curl -sL "https://logo.clearbit.com/obs.tv" -o olympic-broadcasting.png 2>/dev/null || echo "OBS logo not found"
+
+# AENA
+curl -sL "https://logo.clearbit.com/aena.es" -o aena.png 2>/dev/null || echo "AENA logo not found"
+
+# SAP
+curl -sL "https://logo.clearbit.com/sap.com" -o sap.png 2>/dev/null || echo "SAP logo not found"
+
+# Gigya (now SAP CDC)
+curl -sL "https://logo.clearbit.com/gigya.com" -o gigya.png 2>/dev/null || echo "Gigya logo not found"
+
+# Accenture
+curl -sL "https://logo.clearbit.com/accenture.com" -o accenture.png 2>/dev/null || echo "Accenture logo not found"
+
+# Megabanner
+curl -sL "https://logo.clearbit.com/megabanner.es" -o megabanner.png 2>/dev/null || echo "Megabanner logo not found"
+
+# Everis
+curl -sL "https://logo.clearbit.com/everis.com" -o everis.png 2>/dev/null || echo "Everis logo not found"
+
+# Indra
+curl -sL "https://logo.clearbit.com/indra.es" -o indra.png 2>/dev/null || echo "Indra logo not found"
+
+echo "✅ Company logos downloaded"
+ls -lh
diff --git a/internal/models/cv.go b/internal/models/cv.go
index b8ea0c6..ebcb2e9 100644
--- a/internal/models/cv.go
+++ b/internal/models/cv.go
@@ -41,10 +41,12 @@ type Personal struct {
type Experience struct {
Position string `json:"position"`
Company string `json:"company"`
+ CompanyLogo string `json:"companyLogo"`
Location string `json:"location"`
StartDate string `json:"startDate"`
EndDate string `json:"endDate"`
Current bool `json:"current"`
+ ShortDescription string `json:"shortDescription"`
Responsibilities []string `json:"responsibilities"`
Technologies []string `json:"technologies"`
Highlights []string `json:"highlights"`
diff --git a/static/css/main.css b/static/css/main.css
index 21dc13f..87789e2 100644
--- a/static/css/main.css
+++ b/static/css/main.css
@@ -124,13 +124,39 @@ a:hover {
min-height: 11in;
}
-/* Header */
+/* Header - Photo on right, inline with text */
.cv-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: flex-start;
+ gap: 2rem;
border-bottom: 2px solid var(--text-dark);
padding-bottom: 1.5rem;
margin-bottom: 2rem;
}
+.cv-header-left {
+ flex: 1;
+}
+
+.cv-header-right {
+ flex-shrink: 0;
+}
+
+.cv-photo {
+ width: 120px;
+ height: 120px;
+ border-radius: 50%;
+ overflow: hidden;
+ border: 3px solid var(--border-gray);
+}
+
+.cv-photo img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+}
+
.cv-name {
font-size: 2.5rem;
font-weight: 700;
@@ -170,9 +196,15 @@ a:hover {
text-align: justify;
}
-/* Experience */
+/* Experience - with separators */
.experience-item {
margin-bottom: 1.5rem;
+ padding-bottom: 1.5rem;
+ border-bottom: 1px solid var(--border-gray);
+}
+
+.experience-item:last-child {
+ border-bottom: none;
}
.experience-header {
@@ -180,6 +212,27 @@ a:hover {
justify-content: space-between;
margin-bottom: 0.75rem;
gap: 1rem;
+ align-items: center;
+}
+
+.company-logo {
+ width: 40px;
+ height: 40px;
+ flex-shrink: 0;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ margin-right: 1rem;
+}
+
+.company-logo img {
+ max-width: 100%;
+ max-height: 100%;
+ object-fit: contain;
+}
+
+.experience-title {
+ flex: 1;
}
.position {
@@ -335,17 +388,109 @@ footer {
font-size: 2rem;
}
+ .cv-header {
+ flex-direction: column;
+ align-items: center;
+ text-align: center;
+ }
+
+ .cv-photo {
+ order: -1;
+ margin-bottom: 1rem;
+ }
+
.experience-header,
.project-header,
.education-header {
flex-direction: column;
gap: 0.25rem;
}
-
- .action-bar-content {
- flex-direction: column;
- gap: 1rem;
+
+ .company-logo {
+ display: none;
}
}
.no-print {}
+
+/* Print Styles for Photo */
+@media print {
+ .cv-photo {
+ width: 100px;
+ height: 100px;
+ border-width: 2px;
+ }
+
+ .company-logo {
+ width: 30px;
+ height: 30px;
+ }
+}
+
+/* CV Length Toggle */
+.cv-length-toggle {
+ display: flex;
+ gap: 0.5rem;
+}
+
+.length-btn {
+ padding: 0.4rem 1rem;
+ border: 1px solid var(--border-gray);
+ background: white;
+ border-radius: 4px;
+ cursor: pointer;
+ font-size: 0.9rem;
+}
+
+.length-btn:hover {
+ background: #f5f5f5;
+}
+
+.length-btn.active {
+ background: var(--accent-blue);
+ color: white;
+ border-color: var(--accent-blue);
+}
+
+/* Short CV - Hide detailed content */
+.cv-short .long-only {
+ display: none;
+}
+
+.cv-short .short-desc {
+ display: block;
+ color: var(--text-gray);
+ font-size: 0.95rem;
+ line-height: 1.6;
+ margin-bottom: 0.75rem;
+}
+
+/* Long CV - Hide short descriptions */
+.cv-long .short-desc,
+.short-desc {
+ display: none;
+}
+
+.cv-long .long-only {
+ display: block;
+}
+
+/* Ensure lists display correctly in long mode */
+.cv-long .responsibilities {
+ display: block;
+}
+
+/* Responsive adjustments */
+@media (max-width: 768px) {
+ .action-bar-content {
+ flex-wrap: wrap;
+ justify-content: center;
+ }
+
+ .cv-length-toggle {
+ order: 1;
+ width: 100%;
+ justify-content: center;
+ margin-top: 0.5rem;
+ }
+}
diff --git a/static/images/companies/accenture.png b/static/images/companies/accenture.png
new file mode 100644
index 0000000..9e8eccb
Binary files /dev/null and b/static/images/companies/accenture.png differ
diff --git a/static/images/companies/aena.png b/static/images/companies/aena.png
new file mode 100644
index 0000000..7e5ee41
Binary files /dev/null and b/static/images/companies/aena.png differ
diff --git a/static/images/companies/everis.png b/static/images/companies/everis.png
new file mode 100644
index 0000000..222e709
Binary files /dev/null and b/static/images/companies/everis.png differ
diff --git a/static/images/companies/gigya.png b/static/images/companies/gigya.png
new file mode 100644
index 0000000..d770b52
Binary files /dev/null and b/static/images/companies/gigya.png differ
diff --git a/static/images/companies/indra.png b/static/images/companies/indra.png
new file mode 100644
index 0000000..e3bf314
--- /dev/null
+++ b/static/images/companies/indra.png
@@ -0,0 +1 @@
+Not Found
diff --git a/static/images/companies/megabanner.png b/static/images/companies/megabanner.png
new file mode 100644
index 0000000..e3bf314
--- /dev/null
+++ b/static/images/companies/megabanner.png
@@ -0,0 +1 @@
+Not Found
diff --git a/static/images/companies/olympic-broadcasting.png b/static/images/companies/olympic-broadcasting.png
new file mode 100644
index 0000000..321c396
Binary files /dev/null and b/static/images/companies/olympic-broadcasting.png differ
diff --git a/static/images/companies/sap.png b/static/images/companies/sap.png
new file mode 100644
index 0000000..d770b52
Binary files /dev/null and b/static/images/companies/sap.png differ
diff --git a/static/images/profile/placeholder.svg b/static/images/profile/placeholder.svg
new file mode 100644
index 0000000..fbf5539
--- /dev/null
+++ b/static/images/profile/placeholder.svg
@@ -0,0 +1,6 @@
+
diff --git a/templates/cv-content.html b/templates/cv-content.html
index 0ebf2b9..7c7d98c 100644
--- a/templates/cv-content.html
+++ b/templates/cv-content.html
@@ -1,15 +1,22 @@
+ {{.ShortDescription}}
+ {{end}} + +