feat: add Projects section between Courses and Awards
Added new Projects section with two initial projects: - Somos Una Ola - Beach cleaning initiative website (Node.js/Express/HTMX) - Herrumbre Vivo Arte - Artist portfolio for recycled art Changes: - Added projects data to cv-en.json and cv-es.json - Updated Project struct in models/cv.go with all required fields - Added Projects section CSS matching Awards/Courses styling (80×80px icons) - Added Projects template with icons, current badges, and Domestika link - Reordered sections: Courses → Projects → Awards (as requested) Features: - Clickable project titles linking to websites - Current badge for ongoing projects - Period and location display - Short descriptions (always visible) - Responsibilities list (long version only) - Technologies list (long version only) - Footer with link to Domestika portfolio
This commit is contained in:
@@ -702,6 +702,36 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"projects": [
|
||||||
|
{
|
||||||
|
"title": "Somos Una Ola - Beach Cleaning Initiative",
|
||||||
|
"url": "https://somosunaola.org",
|
||||||
|
"location": "La Palma, Canary Islands",
|
||||||
|
"startDate": "2023-07",
|
||||||
|
"current": true,
|
||||||
|
"technologies": ["Node.js", "Express.js", "HTMX"],
|
||||||
|
"shortDescription": "Volunteer project promoting beach cleaning on La Palma island. Created their website to publish completed cleanings and schedule future events.",
|
||||||
|
"responsibilities": [
|
||||||
|
"Designed and developed full-stack website using Node.js Express and HTMX",
|
||||||
|
"Implemented event publishing system for completed and upcoming beach cleanings",
|
||||||
|
"Supported environmental initiative that has completed 18 cleanings across 12 beaches"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Herrumbre Vivo Arte - Artist Portfolio Website",
|
||||||
|
"url": "https://herrumbrevivoarte.com",
|
||||||
|
"location": "Fuencaliente, La Palma",
|
||||||
|
"startDate": "2024",
|
||||||
|
"current": true,
|
||||||
|
"technologies": ["Web Development", "Portfolio Design"],
|
||||||
|
"shortDescription": "Portfolio website for Gustavo Díaz, artisan who transforms recycled materials into sculptures. Promotes environmental art and sustainable creativity.",
|
||||||
|
"responsibilities": [
|
||||||
|
"Created online presence for recycled art project focused on sustainability",
|
||||||
|
"Showcased sculptures made from metal, plastic, glass, and wood waste",
|
||||||
|
"Highlighted environmental workshops and educational mission aligned with Sustainable Development Goals"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
"references": [
|
"references": [
|
||||||
{
|
{
|
||||||
"title": "Recommendations Letter from TwenTIC",
|
"title": "Recommendations Letter from TwenTIC",
|
||||||
|
|||||||
@@ -734,6 +734,36 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"projects": [
|
||||||
|
{
|
||||||
|
"title": "Somos Una Ola - Iniciativa de Limpieza de Playas",
|
||||||
|
"url": "https://somosunaola.org",
|
||||||
|
"location": "La Palma, Islas Canarias",
|
||||||
|
"startDate": "2023-07",
|
||||||
|
"current": true,
|
||||||
|
"technologies": ["Node.js", "Express.js", "HTMX"],
|
||||||
|
"shortDescription": "Proyecto de voluntariado que promueve la limpieza de playas en la isla de La Palma. Creación de su sitio web para publicar limpiezas realizadas y programar eventos futuros.",
|
||||||
|
"responsibilities": [
|
||||||
|
"Diseñé y desarrollé sitio web full-stack usando Node.js Express y HTMX",
|
||||||
|
"Implementé sistema de publicación de eventos para limpiezas realizadas y futuras",
|
||||||
|
"Apoyé iniciativa ambiental que ha completado 18 limpiezas en 12 playas diferentes"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Herrumbre Vivo Arte - Sitio Web Portfolio de Artista",
|
||||||
|
"url": "https://herrumbrevivoarte.com",
|
||||||
|
"location": "Fuencaliente, La Palma",
|
||||||
|
"startDate": "2024",
|
||||||
|
"current": true,
|
||||||
|
"technologies": ["Desarrollo Web", "Diseño de Portfolio"],
|
||||||
|
"shortDescription": "Sitio web portfolio para Gustavo Díaz, artesano que transforma materiales reciclados en esculturas. Promueve arte ambiental y creatividad sostenible.",
|
||||||
|
"responsibilities": [
|
||||||
|
"Creé presencia online para proyecto de arte reciclado enfocado en sostenibilidad",
|
||||||
|
"Mostré esculturas hechas de desechos metálicos, plásticos, vidrio y madera",
|
||||||
|
"Destaqué talleres ambientales y misión educativa alineada con Objetivos de Desarrollo Sostenible"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
"references": [
|
"references": [
|
||||||
{
|
{
|
||||||
"title": "Cartas de recomendación de TwenTiC",
|
"title": "Cartas de recomendación de TwenTiC",
|
||||||
|
|||||||
@@ -99,13 +99,14 @@ type Language struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Project struct {
|
type Project struct {
|
||||||
Name string `json:"name"`
|
Title string `json:"title"`
|
||||||
Role string `json:"role"`
|
URL string `json:"url"`
|
||||||
URL string `json:"url"`
|
Location string `json:"location"`
|
||||||
Period string `json:"period"`
|
StartDate string `json:"startDate"`
|
||||||
Description string `json:"description"`
|
Current bool `json:"current"`
|
||||||
Technologies []string `json:"technologies"`
|
Technologies []string `json:"technologies"`
|
||||||
Highlights []string `json:"highlights"`
|
ShortDescription string `json:"shortDescription"`
|
||||||
|
Responsibilities []string `json:"responsibilities"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Award struct {
|
type Award struct {
|
||||||
|
|||||||
@@ -935,6 +935,116 @@ iconify-icon {
|
|||||||
text-align: justify;
|
text-align: justify;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Projects */
|
||||||
|
.project-item {
|
||||||
|
display: flex;
|
||||||
|
gap: 1.2rem;
|
||||||
|
align-items: flex-start;
|
||||||
|
margin-bottom: 2.5rem;
|
||||||
|
padding-bottom: 2rem;
|
||||||
|
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-icon {
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 80px;
|
||||||
|
height: 80px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.default-project-icon {
|
||||||
|
width: 80px;
|
||||||
|
height: 80px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
background: #f5f5f5;
|
||||||
|
color: #999;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-content {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-header {
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-title {
|
||||||
|
font-size: 1em;
|
||||||
|
font-weight: 600;
|
||||||
|
margin: 0 0 0.3rem 0;
|
||||||
|
line-height: 1.4;
|
||||||
|
color: var(--text-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-title-text {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-title-text a {
|
||||||
|
color: var(--accent-blue);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-title-text a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-period,
|
||||||
|
.project-separator,
|
||||||
|
.project-location {
|
||||||
|
color: #555;
|
||||||
|
font-size: 0.9em;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-separator {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-desc {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: var(--text-dark);
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
line-height: 1.6;
|
||||||
|
text-align: justify;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-technologies {
|
||||||
|
font-size: 0.85em;
|
||||||
|
color: var(--text-gray);
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.projects-footer {
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
padding-top: 1rem;
|
||||||
|
border-top: 2px solid #ddd;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 0.95em;
|
||||||
|
color: var(--text-gray);
|
||||||
|
}
|
||||||
|
|
||||||
|
.projects-footer p {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.projects-footer a {
|
||||||
|
color: var(--accent-blue);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.projects-footer a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
/* References */
|
/* References */
|
||||||
.reference-item {
|
.reference-item {
|
||||||
margin-bottom: 0.6rem;
|
margin-bottom: 0.6rem;
|
||||||
|
|||||||
+96
-35
@@ -157,41 +157,6 @@
|
|||||||
<div class="page-content">
|
<div class="page-content">
|
||||||
<!-- Main Content Area - Page 2 -->
|
<!-- Main Content Area - Page 2 -->
|
||||||
<main class="cv-main">
|
<main class="cv-main">
|
||||||
<!-- Awards Section -->
|
|
||||||
{{if .CV.Awards}}
|
|
||||||
<section id="awards" class="cv-section">
|
|
||||||
<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>
|
|
||||||
{{range .CV.Awards}}
|
|
||||||
<div class="award-item">
|
|
||||||
{{if .AwardLogo}}
|
|
||||||
<div class="award-logo">
|
|
||||||
<img src="/static/images/companies/{{.AwardLogo}}" alt="{{.Title}} logo" onerror="this.parentElement.innerHTML='<iconify-icon icon=\'mdi:trophy\' width=\'60\' height=\'60\' class=\'default-award-icon\'></iconify-icon>'">
|
|
||||||
</div>
|
|
||||||
{{end}}
|
|
||||||
<div class="award-content">
|
|
||||||
<strong>{{.Title}}</strong><br>
|
|
||||||
<small>{{.Issuer}} - {{.Date}}</small>
|
|
||||||
|
|
||||||
{{if .ShortDescription}}
|
|
||||||
<p class="award-desc short-desc">{{.ShortDescription | safeHTML}}</p>
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
{{if .Responsibilities}}
|
|
||||||
<ul class="responsibilities long-only">
|
|
||||||
{{range .Responsibilities}}
|
|
||||||
<li>{{. | safeHTML}}</li>
|
|
||||||
{{end}}
|
|
||||||
</ul>
|
|
||||||
{{end}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{end}}
|
|
||||||
</section>
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
<!-- Courses Section -->
|
<!-- Courses Section -->
|
||||||
{{if .CV.Courses}}
|
{{if .CV.Courses}}
|
||||||
<section id="courses" class="cv-section">
|
<section id="courses" class="cv-section">
|
||||||
@@ -236,6 +201,102 @@
|
|||||||
</section>
|
</section>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
<!-- Projects Section -->
|
||||||
|
{{if .CV.Projects}}
|
||||||
|
<section id="projects" class="cv-section">
|
||||||
|
<h3 class="section-title">
|
||||||
|
<iconify-icon icon="mdi:folder-multiple" width="24" height="24" class="section-icon"></iconify-icon>
|
||||||
|
{{if eq .Lang "es"}}Proyectos{{else}}Projects{{end}}
|
||||||
|
</h3>
|
||||||
|
{{range .CV.Projects}}
|
||||||
|
<div class="project-item">
|
||||||
|
<div class="project-icon">
|
||||||
|
<iconify-icon icon="mdi:web" width="80" height="80" class="default-project-icon"></iconify-icon>
|
||||||
|
</div>
|
||||||
|
<div class="project-content">
|
||||||
|
<div class="project-header">
|
||||||
|
<h4 class="project-title">
|
||||||
|
<span class="project-title-text">
|
||||||
|
{{if .URL}}
|
||||||
|
<a href="{{.URL}}" target="_blank" rel="noopener noreferrer">{{.Title}}</a>
|
||||||
|
{{else}}
|
||||||
|
{{.Title}}
|
||||||
|
{{end}}
|
||||||
|
</span>
|
||||||
|
{{if .Current}}
|
||||||
|
<span class="current-badge">{{if eq $.Lang "es"}}ACTUAL{{else}}CURRENT{{end}}</span>
|
||||||
|
{{end}}
|
||||||
|
</h4>
|
||||||
|
<span class="project-period">{{.StartDate}} {{if .Current}}/ {{if eq $.Lang "es"}}presente{{else}}now{{end}}{{end}}</span>
|
||||||
|
<span class="project-separator"> - </span>
|
||||||
|
<span class="project-location">({{.Location}})</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{if .ShortDescription}}
|
||||||
|
<p class="project-desc short-desc">{{.ShortDescription | safeHTML}}</p>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{if .Responsibilities}}
|
||||||
|
<ul class="responsibilities long-only">
|
||||||
|
{{range .Responsibilities}}
|
||||||
|
<li>{{. | safeHTML}}</li>
|
||||||
|
{{end}}
|
||||||
|
</ul>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{if .Technologies}}
|
||||||
|
<div class="project-technologies long-only">
|
||||||
|
<strong>{{if eq $.Lang "es"}}Tecnologías:{{else}}Technologies:{{end}}</strong>
|
||||||
|
{{range $index, $tech := .Technologies}}{{if $index}}, {{end}}{{$tech}}{{end}}
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
<!-- Link to full portfolio -->
|
||||||
|
<div class="projects-footer">
|
||||||
|
<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>
|
||||||
|
</section>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
<!-- Awards Section -->
|
||||||
|
{{if .CV.Awards}}
|
||||||
|
<section id="awards" class="cv-section">
|
||||||
|
<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>
|
||||||
|
{{range .CV.Awards}}
|
||||||
|
<div class="award-item">
|
||||||
|
{{if .AwardLogo}}
|
||||||
|
<div class="award-logo">
|
||||||
|
<img src="/static/images/companies/{{.AwardLogo}}" alt="{{.Title}} logo" onerror="this.parentElement.innerHTML='<iconify-icon icon=\'mdi:trophy\' width=\'60\' height=\'60\' class=\'default-award-icon\'></iconify-icon>'">
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
<div class="award-content">
|
||||||
|
<strong>{{.Title}}</strong><br>
|
||||||
|
<small>{{.Issuer}} - {{.Date}}</small>
|
||||||
|
|
||||||
|
{{if .ShortDescription}}
|
||||||
|
<p class="award-desc short-desc">{{.ShortDescription | safeHTML}}</p>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{if .Responsibilities}}
|
||||||
|
<ul class="responsibilities long-only">
|
||||||
|
{{range .Responsibilities}}
|
||||||
|
<li>{{. | safeHTML}}</li>
|
||||||
|
{{end}}
|
||||||
|
</ul>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
</section>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
<!-- Languages Section -->
|
<!-- Languages Section -->
|
||||||
<section id="languages" class="cv-section">
|
<section id="languages" class="cv-section">
|
||||||
<h3 class="section-title">
|
<h3 class="section-title">
|
||||||
|
|||||||
Reference in New Issue
Block a user