feat: add explicit sidebar placement control and responsive design (1024-1280px)
- Add sidebar field to SkillCategory model for explicit left/right control - Update splitSkills to respect sidebar field instead of automatic splitting - Add responsive CSS for 1024-1280px: collapse labels, icons-only buttons, EN/ES language selector - Remove language switcher animations - Ensure desktop view (>1280px) always shows full sidebar content - Move Databases and Infrastructure to right sidebar - Reduce font sizes in responsive range - Update project logos (Lidering, Jorpack, Delivery Bikes)
This commit is contained in:
+24
-14
@@ -350,6 +350,7 @@
|
||||
{
|
||||
"category": "Go Ecosystem",
|
||||
"proficiency": 5,
|
||||
"sidebar": "left",
|
||||
"items": [
|
||||
"Hono - High-Performance Web Framework",
|
||||
"Gin - Web Framework",
|
||||
@@ -363,6 +364,7 @@
|
||||
{
|
||||
"category": "JavaScript Ecosystem",
|
||||
"proficiency": 5,
|
||||
"sidebar": "left",
|
||||
"items": [
|
||||
"Node.js & Express",
|
||||
"React & React Ecosystem",
|
||||
@@ -375,6 +377,7 @@
|
||||
{
|
||||
"category": "Frontend Technologies",
|
||||
"proficiency": 5,
|
||||
"sidebar": "left",
|
||||
"items": [
|
||||
"HTMX - Hypermedia-Driven Applications",
|
||||
"HTML5 & Semantic Web",
|
||||
@@ -386,20 +389,10 @@
|
||||
"Template Engines (Handlebars, Panini, Mustache)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"category": "Legacy Enterprise Technologies",
|
||||
"proficiency": 3,
|
||||
"items": [
|
||||
"Java & J2EE",
|
||||
"Spring Framework, Struts, Hibernate",
|
||||
"PHP & WordPress",
|
||||
"Yii Framework, Zend Framework",
|
||||
"Enterprise Application Servers (Tomcat, JBoss, WebLogic)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"category": "Backend Technologies",
|
||||
"proficiency": 5,
|
||||
"sidebar": "left",
|
||||
"items": [
|
||||
"Go - Current Primary Stack",
|
||||
"Hono Framework - High-Performance Web Server",
|
||||
@@ -409,9 +402,22 @@
|
||||
"Database Design & Optimization"
|
||||
]
|
||||
},
|
||||
{
|
||||
"category": "Legacy Enterprise Technologies",
|
||||
"proficiency": 3,
|
||||
"sidebar": "left",
|
||||
"items": [
|
||||
"Java & J2EE",
|
||||
"Spring Framework, Struts, Hibernate",
|
||||
"PHP & WordPress",
|
||||
"Yii Framework, Zend Framework",
|
||||
"Enterprise Application Servers (Tomcat, JBoss, WebLogic)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"category": "Databases",
|
||||
"proficiency": 4,
|
||||
"sidebar": "right",
|
||||
"items": [
|
||||
"PostgreSQL",
|
||||
"MySQL",
|
||||
@@ -425,6 +431,7 @@
|
||||
{
|
||||
"category": "Infrastructure & Servers",
|
||||
"proficiency": 5,
|
||||
"sidebar": "right",
|
||||
"items": [
|
||||
"Linux Server Administration",
|
||||
"VPS Deployment & Configuration",
|
||||
@@ -436,6 +443,7 @@
|
||||
{
|
||||
"category": "DevOps & CI/CD",
|
||||
"proficiency": 5,
|
||||
"sidebar": "right",
|
||||
"items": [
|
||||
"CI/CD Pipeline Design & Implementation",
|
||||
"Custom Deployment Solutions",
|
||||
@@ -447,6 +455,7 @@
|
||||
{
|
||||
"category": "Team Management",
|
||||
"proficiency": 4,
|
||||
"sidebar": "right",
|
||||
"items": [
|
||||
"Preparation and projects startup",
|
||||
"Fluid communication with clients",
|
||||
@@ -458,6 +467,7 @@
|
||||
{
|
||||
"category": "Design Tools",
|
||||
"proficiency": 3,
|
||||
"sidebar": "right",
|
||||
"items": [
|
||||
"Corel Draw",
|
||||
"Adobe PhotoShop",
|
||||
@@ -793,9 +803,9 @@
|
||||
"technologies": ["JavaScript", "React", "Node.js", "PHP", "WordPress", "Web Development"],
|
||||
"shortDescription": "Collection of client projects and websites where I contributed to development, implementation, and technical solutions across various industries.",
|
||||
"responsibilities": [
|
||||
"<img src='/static/images/projects/twentic.png' alt='Lidering'><div><strong><a href='https://lidering.com' target='_blank' rel='noopener noreferrer'>Lidering</a></strong> (via Twentic): Real estate and property management platform development</div>",
|
||||
"<img src='/static/images/projects/twentic.png' alt='Jorpack'><div><strong><a href='https://jorpack.com' target='_blank' rel='noopener noreferrer'>Jorpack</a></strong> (via Twentic): Industrial packaging solutions and corporate website</div>",
|
||||
"<iconify-icon icon='mdi:bike' width='60' height='60' class='default-company-icon'></iconify-icon><div><strong><a href='https://deliverybikesbcn.com/' target='_blank' rel='noopener noreferrer'>Delivery Bikes BCN</a></strong>: Bicycle delivery service platform for Barcelona</div>",
|
||||
"<img src='/static/images/projects/lidering.png' alt='Lidering'><div><strong><a href='https://lidering.com' target='_blank' rel='noopener noreferrer'>Lidering</a></strong> (via Twentic): Real estate and property management platform development</div>",
|
||||
"<img src='/static/images/projects/jorpack.png' alt='Jorpack'><div><strong><a href='https://jorpack.com' target='_blank' rel='noopener noreferrer'>Jorpack</a></strong> (via Twentic): Industrial packaging solutions and corporate website</div>",
|
||||
"<img src='/static/images/projects/deliverybikes.png' alt='Delivery Bikes BCN'><div><strong><a href='https://deliverybikesbcn.com/' target='_blank' rel='noopener noreferrer'>Delivery Bikes BCN</a></strong>: Bicycle delivery service platform for Barcelona</div>",
|
||||
"<iconify-icon icon='mdi:security' width='60' height='60' class='default-company-icon'></iconify-icon><div><strong><a href='https://mobbeel.com' target='_blank' rel='noopener noreferrer'>Mobbeel</a></strong>: Biometric authentication and identity verification solutions website</div>"
|
||||
]
|
||||
}
|
||||
|
||||
+24
-14
@@ -350,6 +350,7 @@
|
||||
{
|
||||
"category": "Ecosistema Go",
|
||||
"proficiency": 5,
|
||||
"sidebar": "left",
|
||||
"items": [
|
||||
"Hono - Framework Web de Alto Rendimiento",
|
||||
"Gin - Framework Web",
|
||||
@@ -363,6 +364,7 @@
|
||||
{
|
||||
"category": "Ecosistema JavaScript",
|
||||
"proficiency": 5,
|
||||
"sidebar": "left",
|
||||
"items": [
|
||||
"Node.js y Express",
|
||||
"React y Ecosistema React",
|
||||
@@ -375,6 +377,7 @@
|
||||
{
|
||||
"category": "Tecnologías Frontend",
|
||||
"proficiency": 5,
|
||||
"sidebar": "left",
|
||||
"items": [
|
||||
"HTMX - Aplicaciones Basadas en Hipermedia",
|
||||
"HTML5 y Web Semántica",
|
||||
@@ -386,20 +389,10 @@
|
||||
"Motores de Plantillas (Handlebars, Panini, Mustache)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"category": "Tecnologías Enterprise Anteriores",
|
||||
"proficiency": 3,
|
||||
"items": [
|
||||
"Java y J2EE",
|
||||
"Spring Framework, Struts, Hibernate",
|
||||
"PHP y WordPress",
|
||||
"Yii Framework, Zend Framework",
|
||||
"Servidores de Aplicaciones Enterprise (Tomcat, JBoss, WebLogic)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"category": "Tecnologías Backend",
|
||||
"proficiency": 5,
|
||||
"sidebar": "left",
|
||||
"items": [
|
||||
"Go - Stack Principal Actual",
|
||||
"Hono Framework - Servidor Web de Alto Rendimiento",
|
||||
@@ -409,9 +402,22 @@
|
||||
"Diseño y Optimización de Bases de Datos"
|
||||
]
|
||||
},
|
||||
{
|
||||
"category": "Tecnologías Enterprise Anteriores",
|
||||
"proficiency": 3,
|
||||
"sidebar": "left",
|
||||
"items": [
|
||||
"Java y J2EE",
|
||||
"Spring Framework, Struts, Hibernate",
|
||||
"PHP y WordPress",
|
||||
"Yii Framework, Zend Framework",
|
||||
"Servidores de Aplicaciones Enterprise (Tomcat, JBoss, WebLogic)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"category": "Bases de Datos",
|
||||
"proficiency": 4,
|
||||
"sidebar": "right",
|
||||
"items": [
|
||||
"PostgreSQL",
|
||||
"MySQL",
|
||||
@@ -425,6 +431,7 @@
|
||||
{
|
||||
"category": "Infraestructura y Servidores",
|
||||
"proficiency": 5,
|
||||
"sidebar": "right",
|
||||
"items": [
|
||||
"Administración de Servidores Linux",
|
||||
"Despliegue y Configuración de VPS",
|
||||
@@ -436,6 +443,7 @@
|
||||
{
|
||||
"category": "DevOps y CI/CD",
|
||||
"proficiency": 5,
|
||||
"sidebar": "right",
|
||||
"items": [
|
||||
"Diseño e Implementación de Pipelines CI/CD",
|
||||
"Soluciones de Despliegue Personalizadas",
|
||||
@@ -447,6 +455,7 @@
|
||||
{
|
||||
"category": "Gestión de Equipos",
|
||||
"proficiency": 4,
|
||||
"sidebar": "right",
|
||||
"items": [
|
||||
"Preparación y puesta en marcha de proyectos",
|
||||
"Comunicación fluida con los clientes",
|
||||
@@ -458,6 +467,7 @@
|
||||
{
|
||||
"category": "Herramientas de Diseño",
|
||||
"proficiency": 3,
|
||||
"sidebar": "right",
|
||||
"items": [
|
||||
"Corel Draw",
|
||||
"Adobe PhotoShop",
|
||||
@@ -798,9 +808,9 @@
|
||||
"technologies": ["JavaScript", "React", "Node.js", "PHP", "WordPress", "Desarrollo Web"],
|
||||
"shortDescription": "Colección de proyectos de clientes y sitios web donde contribuí al desarrollo, implementación y soluciones técnicas en diversas industrias.",
|
||||
"responsibilities": [
|
||||
"<img src='/static/images/projects/twentic.png' alt='Lidering'><div><strong><a href='https://lidering.com' target='_blank' rel='noopener noreferrer'>Lidering</a></strong> (a través de Twentic): Desarrollo de plataforma de gestión inmobiliaria y propiedades</div>",
|
||||
"<img src='/static/images/projects/twentic.png' alt='Jorpack'><div><strong><a href='https://jorpack.com' target='_blank' rel='noopener noreferrer'>Jorpack</a></strong> (a través de Twentic): Soluciones de embalaje industrial y sitio web corporativo</div>",
|
||||
"<iconify-icon icon='mdi:bike' width='60' height='60' class='default-company-icon'></iconify-icon><div><strong><a href='https://deliverybikesbcn.com/' target='_blank' rel='noopener noreferrer'>Delivery Bikes BCN</a></strong>: Plataforma de servicio de entrega en bicicleta para Barcelona</div>",
|
||||
"<img src='/static/images/projects/lidering.png' alt='Lidering'><div><strong><a href='https://lidering.com' target='_blank' rel='noopener noreferrer'>Lidering</a></strong> (a través de Twentic): Desarrollo de plataforma de gestión inmobiliaria y propiedades</div>",
|
||||
"<img src='/static/images/projects/jorpack.png' alt='Jorpack'><div><strong><a href='https://jorpack.com' target='_blank' rel='noopener noreferrer'>Jorpack</a></strong> (a través de Twentic): Soluciones de embalaje industrial y sitio web corporativo</div>",
|
||||
"<img src='/static/images/projects/deliverybikes.png' alt='Delivery Bikes BCN'><div><strong><a href='https://deliverybikesbcn.com/' target='_blank' rel='noopener noreferrer'>Delivery Bikes BCN</a></strong>: Plataforma de servicio de entrega en bicicleta para Barcelona</div>",
|
||||
"<iconify-icon icon='mdi:security' width='60' height='60' class='default-company-icon'></iconify-icon><div><strong><a href='https://mobbeel.com' target='_blank' rel='noopener noreferrer'>Mobbeel</a></strong>: Sitio web de soluciones de autenticación biométrica y verificación de identidad</div>"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -199,20 +199,21 @@ func (h *CVHandler) ExportPDF(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
// splitSkills splits skill categories between left (page 1) and right (page 2) sidebars
|
||||
// Left sidebar shows first 7 categories, right sidebar shows remaining categories
|
||||
// Each category explicitly specifies which sidebar it belongs to via the "sidebar" field
|
||||
func splitSkills(skills []models.SkillCategory) (left, right []models.SkillCategory) {
|
||||
if len(skills) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Split at index 7 (first 7 items on left)
|
||||
splitIndex := 7
|
||||
if len(skills) < splitIndex {
|
||||
return skills, nil
|
||||
// Filter by sidebar field
|
||||
for _, skill := range skills {
|
||||
if skill.Sidebar == "right" {
|
||||
right = append(right, skill)
|
||||
} else {
|
||||
// Default to left if not specified or if set to "left"
|
||||
left = append(left, skill)
|
||||
}
|
||||
}
|
||||
|
||||
left = skills[:splitIndex]
|
||||
right = skills[splitIndex:]
|
||||
|
||||
return left, right
|
||||
}
|
||||
|
||||
@@ -89,6 +89,7 @@ type SkillCategory struct {
|
||||
Category string `json:"category"`
|
||||
Proficiency int `json:"proficiency"`
|
||||
Items []string `json:"items"`
|
||||
Sidebar string `json:"sidebar"` // "left" or "right"
|
||||
}
|
||||
|
||||
type Language struct {
|
||||
|
||||
@@ -1899,3 +1899,158 @@ html {
|
||||
height: 45px;
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
Desktop: Ensure Sidebar Content Visible (>1280px)
|
||||
======================================== */
|
||||
|
||||
@media (min-width: 1281px) {
|
||||
/* Ensure sidebar content is always visible in desktop view */
|
||||
.sidebar-content {
|
||||
max-height: none !important;
|
||||
opacity: 1 !important;
|
||||
overflow: visible !important;
|
||||
display: block !important;
|
||||
margin-top: 10px !important;
|
||||
}
|
||||
|
||||
.skill-category .sidebar-content,
|
||||
.cv-sidebar-section .sidebar-content {
|
||||
max-height: none !important;
|
||||
opacity: 1 !important;
|
||||
overflow: visible !important;
|
||||
}
|
||||
|
||||
.sidebar-title::after {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.sidebar-title {
|
||||
cursor: default !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
Responsive: Medium Screens (1024px - 1280px)
|
||||
======================================== */
|
||||
|
||||
@media (min-width: 1024px) and (max-width: 1280px) {
|
||||
|
||||
/* ========== Global Font Size Reduction ========== */
|
||||
html {
|
||||
font-size: 14px; /* Reduced from default 16px */
|
||||
}
|
||||
|
||||
.cv-name {
|
||||
font-size: 1.8em; /* Reduced from 2.2em */
|
||||
}
|
||||
|
||||
.sidebar-title {
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.sidebar-content {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.experience-item h3,
|
||||
.project-item h3 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.experience-item p,
|
||||
.project-item p,
|
||||
.experience-item li,
|
||||
.project-item li {
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
/* ========== Selector Labels - Hide, Show on Hover ========== */
|
||||
.selector-label {
|
||||
max-width: 0;
|
||||
overflow: hidden;
|
||||
opacity: 0;
|
||||
transition: all 0.3s ease;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.selector-group:hover .selector-label {
|
||||
max-width: 200px;
|
||||
opacity: 1;
|
||||
margin-right: 0.75rem;
|
||||
}
|
||||
|
||||
/* ========== Language Selector - Collapse to EN/ES ========== */
|
||||
.language-selector .selector-btn {
|
||||
position: relative;
|
||||
padding: 0.4rem 0.8rem;
|
||||
min-width: 50px;
|
||||
font-size: 0; /* Hide actual text */
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
/* Show only short version (EN/ES) */
|
||||
.language-selector .selector-btn::before {
|
||||
content: attr(data-short);
|
||||
font-size: 1rem; /* Restore font size for pseudo-element */
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* On hover, show full text */
|
||||
.language-selector:hover .selector-btn,
|
||||
.language-selector .selector-btn:hover {
|
||||
font-size: 1rem; /* Restore font size */
|
||||
padding: 0.4rem 1rem;
|
||||
min-width: auto;
|
||||
}
|
||||
|
||||
.language-selector:hover .selector-btn::before,
|
||||
.language-selector .selector-btn:hover::before {
|
||||
content: ''; /* Hide short version */
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
/* ========== Action Buttons - Icon Only, Expand on Hover ========== */
|
||||
.action-btn {
|
||||
position: relative;
|
||||
width: 45px;
|
||||
overflow: hidden;
|
||||
transition: width 0.3s ease, padding 0.3s ease;
|
||||
white-space: nowrap;
|
||||
text-indent: 0;
|
||||
}
|
||||
|
||||
/* Hide button text, keep icon */
|
||||
.action-btn iconify-icon {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
font-size: 0;
|
||||
padding: 0 0.65rem;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* On hover, show text */
|
||||
.action-btn:hover {
|
||||
width: auto;
|
||||
font-size: 0.95rem;
|
||||
padding: 0.65rem 1.5rem;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
/* ========== Sidebar Content - Hide Text, Show on Hover ========== */
|
||||
.sidebar-content {
|
||||
max-height: 0;
|
||||
overflow: hidden;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
/* Show sidebar content on hover */
|
||||
.skill-category:hover .sidebar-content,
|
||||
.cv-sidebar-section:hover .sidebar-content {
|
||||
max-height: 1000px;
|
||||
opacity: 1;
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 9.6 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 4.3 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 6.4 KiB |
@@ -110,10 +110,10 @@
|
||||
|
||||
<!-- Language selector (after title) -->
|
||||
<div class="language-selector">
|
||||
<button class="selector-btn {{if eq .Lang "en"}}active{{end}}" onclick="selectLanguage('en')" aria-label="English">
|
||||
<button class="selector-btn {{if eq .Lang "en"}}active{{end}}" data-short="EN" onclick="selectLanguage('en')" aria-label="English">
|
||||
English
|
||||
</button>
|
||||
<button class="selector-btn {{if eq .Lang "es"}}active{{end}}" onclick="selectLanguage('es')" aria-label="Español">
|
||||
<button class="selector-btn {{if eq .Lang "es"}}active{{end}}" data-short="ES" onclick="selectLanguage('es')" aria-label="Español">
|
||||
Español
|
||||
</button>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user