<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Mi Blog | Juan García</title><link>/blog/</link><atom:link href="/blog/index.xml" rel="self" type="application/rss+xml"/><description>Mi Blog</description><generator>HugoBlox Kit (https://hugoblox.com)</generator><language>es-ES</language><lastBuildDate>Mon, 01 Jun 2026 00:00:00 +0000</lastBuildDate><image><url>/media/icon_hu_d38b8b3031b7345.png</url><title>Mi Blog</title><link>/blog/</link></image><item><title>Desarrollando mi proyecto de fin de ciclo con Hugo</title><link>/blog/mi-primer-proyecto/</link><pubDate>Mon, 01 Jun 2026 00:00:00 +0000</pubDate><guid>/blog/mi-primer-proyecto/</guid><description>&lt;p&gt;¡Hola a todos! Aprovechando el despliegue de este blog, no quería dejar pasar la oportunidad de escribir unas líneas muy especiales para &lt;strong&gt;mis profesores de informática&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Muchísimas gracias por dedicarnos vuestro tiempo, por la visita y, sobre todo, por guiarnos a lo largo de este &lt;strong&gt;Proyecto de Fin de Ciclo (TFC)&lt;/strong&gt;. Detrás de cada línea de código que funciona (y de cada error de Spring Boot que conseguimos solucionar), está la base, la paciencia y el nivel de exigencia que nos habéis transmitido en el aula.&lt;/p&gt;
&lt;p&gt;Este proyecto es el resultado de todo ese esfuerzo compartido. ¡Es un verdadero placer mostraros el fruto de lo aprendido!&lt;/p&gt;
&lt;div id="comments-section" class="comments-container"&gt;
&lt;h3&gt;Comentarios&lt;/h3&gt;
&lt;div id="comments-list"&gt;
&lt;p class="loading"&gt;Cargando comentarios...&lt;/p&gt;
&lt;/div&gt;
&lt;hr class="comments-separator"&gt;
&lt;form id="comment-form" class="comment-form"&gt;
&lt;h4&gt;Deja un comentario&lt;/h4&gt;
&lt;div class="form-group"&gt;
&lt;input type="text" id="comment-author" placeholder="Tu nombre" required&gt;
&lt;/div&gt;
&lt;div class="form-group"&gt;
&lt;textarea id="comment-content" placeholder="Escribe aquí tu comentario..." rows="4" required&gt;&lt;/textarea&gt;
&lt;/div&gt;
&lt;button type="submit" class="btn-submit"&gt;Enviar comentario&lt;/button&gt;
&lt;/form&gt;
&lt;/div&gt;
&lt;style&gt;
.comments-container {
margin-top: 3rem;
padding-top: 2rem;
border-top: 1px solid var(--border-color, currentColor);
color: inherit;
}
.comment-box {
padding: 1rem;
margin-bottom: 1rem;
background: rgba(128, 128, 128, 0.08);
border-radius: 6px;
border-left: 4px solid #007bff;
}
.comment-meta {
font-size: 0.85rem;
opacity: 0.7;
margin-bottom: 0.5rem;
}
.form-group input, .form-group textarea {
width: 100%;
padding: 0.75rem;
margin-bottom: 1rem;
border: 1px solid var(--border-color, rgba(128,128,128,0.4));
background: transparent;
color: inherit;
border-radius: 4px;
}
.btn-submit {
background: #007bff;
color: white;
padding: 0.6rem 1.5rem;
border: none;
border-radius: 4px;
cursor: pointer;
font-weight: bold;
}
.btn-submit:hover { background: #0056b3; }
&lt;/style&gt;
&lt;script&gt;
document.addEventListener("DOMContentLoaded", function() {
const articleSlug = "mi-primer-proyecto";
const API_URL = "/api/comments";
const commentsList = document.getElementById("comments-list");
const commentForm = document.getElementById("comment-form");
function loadComments() {
fetch(`${API_URL}?articleSlug=${articleSlug}`)
.then(res =&gt; res.json())
.then(data =&gt; {
commentsList.innerHTML = "";
if (data.length === 0) {
commentsList.innerHTML = "&lt;p&gt;No hay comentarios aún. ¡Sé el primero!&lt;/p&gt;";
return;
}
data.forEach(comment =&gt; {
const div = document.createElement("div");
div.className = "comment-box";
div.innerHTML = `
&lt;div class="comment-meta"&gt;
&lt;strong&gt;${escapeHTML(comment.author)}&lt;/strong&gt; • ${new Date(comment.createdAt).toLocaleDateString()}
&lt;/div&gt;
&lt;div class="comment-text"&gt;${escapeHTML(comment.content)}&lt;/div&gt;
`;
commentsList.appendChild(div);
});
})
.catch(err =&gt; {
commentsList.innerHTML = "&lt;p&gt;Error al cargar los comentarios&lt;/p&gt;";
console.error(err);
});
}
commentForm.addEventListener("submit", function(e) {
e.preventDefault();
const author = document.getElementById("comment-author").value;
const content = document.getElementById("comment-content").value;
fetch(API_URL, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ articleSlug, author, content })
})
.then(res =&gt; {
if(res.ok) {
document.getElementById("comment-author").value = "";
document.getElementById("comment-content").value = "";
loadComments();
} else {
alert("Error al enviar el comentario");
}
})
.catch(err =&gt; console.error(err));
});
function escapeHTML(str) {
return str.replace(/[&amp;&lt;&gt;'"]/g, tag =&gt; ({ '&amp;': '&amp;amp;', '&lt;': '&amp;lt;', '&gt;': '&amp;gt;', "'": '&amp;#39;', '"': '&amp;quot;' }[tag] || tag));
}
loadComments();
});
&lt;/script&gt;</description></item></channel></rss>