aboutsummaryrefslogtreecommitdiff
path: root/src/pages
diff options
context:
space:
mode:
Diffstat (limited to 'src/pages')
-rw-r--r--src/pages/blog/[id].astro10
-rw-r--r--src/pages/blog/index.astro317
-rw-r--r--src/pages/portfolio/[id].astro57
-rw-r--r--src/pages/portfolio/index.astro2
4 files changed, 15 insertions, 371 deletions
diff --git a/src/pages/blog/[id].astro b/src/pages/blog/[id].astro
index 935a796..3dc324a 100644
--- a/src/pages/blog/[id].astro
+++ b/src/pages/blog/[id].astro
@@ -1,5 +1,5 @@
---
-import Layout from "../../layouts/Layout.astro";
+import Layout from "@/layouts/Layout.astro";
import { getCollection, render } from "astro:content";
import { type GetStaticPaths } from "astro";
@@ -32,6 +32,7 @@ const schema = {
"@type": "BlogPosting",
headline: entry.data.title,
datePublished: entry.data.publishedAt.toISOString(),
+ keywords: entry.data.tags || [],
author: {
"@type": "Person",
name: "Ariel Costas Guerrero",
@@ -39,7 +40,8 @@ const schema = {
publisher: {
"@type": "Person",
name: "Ariel Costas Guerrero",
- logo: {
+ url: "https://www.costas.dev",
+ image: {
"@type": "ImageObject",
url: "https://www.costas.dev/favicon.png",
},
@@ -74,6 +76,10 @@ const schema = {
</small>
<Content />
+
+ <p>
+ <a href="/blog">Volver al blog</a>
+ </p>
</Layout>
<style lang="scss">
diff --git a/src/pages/blog/index.astro b/src/pages/blog/index.astro
index b74781b..10a464b 100644
--- a/src/pages/blog/index.astro
+++ b/src/pages/blog/index.astro
@@ -1,318 +1,5 @@
---
-import { getCollection } from "astro:content";
-import Layout from "../../layouts/Layout.astro";
-
-const blogCollection = (await getCollection("blog")).sort((a, b) => {
- return b.data.publishedAt.getTime() - a.data.publishedAt.getTime();
-});
-
-// Agrupar artículos por fecha
-const groupedPosts = blogCollection.reduce(
- (acc: Record<string, any[]>, post) => {
- const year = post.data.publishedAt.getFullYear();
- const month = post.data.publishedAt.getMonth() + 1;
- const key = `${year}-${month}`;
- if (!acc[key]) {
- acc[key] = [];
- }
- acc[key].push(post);
- return acc;
- },
- {},
-);
-
-// Colección de todas las etiquetas únicas
-const allTags = [...new Set(blogCollection.flatMap(post => post.data.tags || []))].sort();
-
-function humaniseDate(date: Date) {
- const result = date.toLocaleDateString("es-ES", {
- month: "long",
- year: "numeric",
- });
- return result.charAt(0).toUpperCase() + result.slice(1);
-}
-
-const schema = {
- "@context": "https://schema.org",
- "@type": "Blog",
- headline: "Blog de Ariel Costas",
- description:
- "En este blog encontrarás artículos sobre desarrollo, tecnología y otras temáticas que pueda querer compartir. Disclaimer de siempre: las opiniones son mías, y no representan a ninguna empresa o institución.",
- publisher: {
- "@type": "Person",
- name: "Ariel Costas",
- },
- author: {
- "@type": "Person",
- name: "Ariel Costas",
- },
-};
+import BlogListLayout from "@/layouts/BlogListLayout.astro";
---
-<Layout
- title="Blog"
- description="Artículos sobre desarrollo, tecnología y otras temáticas que pueda querer compartir. Disclaimer de siempre: las opiniones son mías, y no representan a ninguna empresa o institución."
->
- <script
- is:inline
- type="application/ld+json"
- slot="head-jsonld"
- set:html={JSON.stringify(schema)}
- />
-
- <h1>Blog de Ariel Costas</h1>
-
- <p>
- En este blog encontrarás artículos sobre desarrollo, tecnología y otras
- temáticas que pueda querer compartir. Disclaimer de siempre: las opiniones
- son mías, y no representan a ninguna empresa o institución.
- </p>
-
- {allTags.length > 0 && (
- <div class="tags-container">
- <h2>Etiquetas</h2>
- <div class="tag-filter">
- <button class="tag-button active" data-tag="all">Todas</button>
- {allTags.map((tag) => (
- <button class="tag-button" data-tag={tag}>{tag}</button>
- ))}
- </div>
- </div>
- )}
-
- <div id="blog-posts">
- {
- Object.entries(groupedPosts).map(([key, posts]) => (
- <section class="post-section" data-date={key}>
- <h2>{humaniseDate(new Date(key))}</h2>
- <ul>
- {posts.map((post) => {
- const postTags = post.data.tags || [];
- const tagsAttribute = postTags.join(',');
- return (
- <li class="post-item" data-tags={tagsAttribute}>
- <a href={`/blog/${post.id}`}>{post.data.title}</a>
- {postTags.length > 0 && (
- <ul class="post-tags">
- {postTags.map((tag: string) => (
- <li>
- <button class="tag-link" data-tag={tag}>
- {tag}
- </button>
- </li>
- ))}
- </ul>
- )}
- </li>
- );
- })}
- </ul>
- </section>
- ))
- }
- </div>
-
- <script>
- // Script para el filtrado de artículos por etiqueta
- document.addEventListener('DOMContentLoaded', () => {
- const tagButtons = document.querySelectorAll('.tag-button');
- const tagLinks = document.querySelectorAll('.tag-link');
- const postItems = document.querySelectorAll('.post-item');
- const postSections = document.querySelectorAll('.post-section');
-
- // Función para filtrar los artículos por etiqueta
- function filterByTag(tag: string) {
- // Primero, restablecer la visibilidad de todos los elementos
- postItems.forEach(item => {
- (item as HTMLElement).style.display = '';
- });
- postSections.forEach(section => {
- (section as HTMLElement).style.display = '';
- });
-
- // Si no es 'todas', filtrar por etiqueta
- if (tag !== 'all') {
- postItems.forEach(item => {
- const itemEl = item as HTMLElement;
- const tagsAttr = itemEl.dataset.tags || '';
- const itemTags = tagsAttr ? tagsAttr.split(',') : [];
- if (!itemTags.includes(tag)) {
- itemEl.style.display = 'none';
- }
- });
-
- // Ocultar secciones que no tienen artículos visibles
- postSections.forEach(section => {
- const items = section.querySelectorAll('.post-item');
- let allHidden = true;
-
- items.forEach(item => {
- if ((item as HTMLElement).style.display !== 'none') {
- allHidden = false;
- }
- });
-
- if (allHidden) {
- (section as HTMLElement).style.display = 'none';
- }
- });
- }
-
- // Actualizar estado activo de los botones
- tagButtons.forEach(button => {
- if ((button as HTMLElement).dataset.tag === tag) {
- button.classList.add('active');
- } else {
- button.classList.remove('active');
- }
- });
-
- // Actualizar URL con el parámetro de consulta
- if (tag === 'all') {
- history.replaceState(null, document.title, window.location.pathname);
- } else {
- history.replaceState(null, document.title, `?tag=${encodeURIComponent(tag)}`);
- }
-
- // Añadir un log para depuración
- console.log(`Filtrado por etiqueta: ${tag}`);
- console.log(`Artículos visibles: ${document.querySelectorAll('.post-item:not([style*="display: none"])')?.length || 0}`);
- }
-
- // Eventos de clic para los botones de etiquetas
- tagButtons.forEach(button => {
- button.addEventListener('click', () => {
- const tag = (button as HTMLElement).dataset.tag;
- if (tag) filterByTag(tag);
- });
- });
-
- // Eventos de clic para los enlaces de etiquetas dentro de los posts
- tagLinks.forEach(link => {
- link.addEventListener('click', (e) => {
- e.preventDefault();
- const tag = (link as HTMLElement).dataset.tag;
- if (tag) filterByTag(tag);
-
- // Desplazamiento suave hacia arriba para ver todos los resultados
- const tagsContainer = document.querySelector('.tags-container');
- if (tagsContainer) {
- window.scrollTo({
- top: (tagsContainer as HTMLElement).offsetTop - 20,
- behavior: 'smooth'
- });
- }
- });
- });
-
- // Verificar si hay un parámetro de consulta para filtrar
- const urlParams = new URLSearchParams(window.location.search);
- const tagParam = urlParams.get('tag');
-
- if (tagParam) {
- const tagExists = Array.from(tagButtons).some(button =>
- (button as HTMLElement).dataset.tag === tagParam
- );
- if (tagExists) {
- filterByTag(tagParam);
- }
- }
- });
- </script>
-</Layout>
-
-<style lang="scss">
- @use "../../../styles/variables" as v;
- @use "sass:color";
-
- .tags-container {
- margin-bottom: 2rem;
- }
-
- .tag-filter {
- display: flex;
- flex-wrap: wrap;
- gap: 0.5rem;
- margin-bottom: 1.5rem;
- }
-
- .tag-button {
- padding: 0.25rem 0.6rem;
- background-color: v.$light;
- color: v.$accent;
- border: 1px solid v.$accent;
- border-radius: 1.5rem;
- font-size: 0.85rem;
- font-family: v.$monoFontStack;
- cursor: pointer;
- transition: all 0.2s ease;
- box-shadow: v.$shadow;
-
- &:hover {
- background-color: color.adjust(v.$accent, $lightness: 45%);
- color: v.$accentDark;
- transform: translateY(-1px);
- }
-
- &.active {
- background-color: v.$accent;
- color: v.$lightAlt;
- border-color: v.$accentDark;
- }
- }
-
- .post-tags {
- display: inline-flex;
- list-style: none;
- margin: 0;
- padding: 0;
- gap: 0.25rem;
- margin-left: 0.5rem;
- }
-
- .post-tags li {
- display: inline;
- }
-
- .tag-link {
- display: inline-block;
- padding: 0.1rem 0.4rem;
- background-color: color.adjust(v.$background, $lightness: -3%);
- color: v.$accentDark;
- border: none;
- border-radius: 1rem;
- font-size: 0.75rem;
- font-family: v.$monoFontStack;
- text-decoration: none;
- cursor: pointer;
- transition: all 0.2s ease;
-
- &:hover {
- background-color: color.adjust(v.$accent, $lightness: 45%);
- color: v.$accentDark;
- transform: translateY(-1px);
- }
- }
-
- /* Efecto de transición para el filtrado */
- .post-item {
- transition: all 0.3s ease;
- }
-
- .post-section {
- transition: opacity 0.3s ease;
- }
-
- #blog-posts {
- min-height: 200px;
- }
-
- /* Mejora el aspecto de los enlaces de posts */
- .post-item {
- margin-bottom: 0.5rem;
-
- a {
- font-weight: 500;
- }
- }
-</style>
+<BlogListLayout />
diff --git a/src/pages/portfolio/[id].astro b/src/pages/portfolio/[id].astro
index b92ecbd..601ff84 100644
--- a/src/pages/portfolio/[id].astro
+++ b/src/pages/portfolio/[id].astro
@@ -1,12 +1,7 @@
---
-import Layout from "../../layouts/Layout.astro";
-import { getCollection, render } from "astro:content";
-import { type GetStaticPaths } from "astro";
-import TechnologyBadge from "../../partials/TechnologyBadge.astro";
-
-interface Props {
- entry: any;
-}
+import type { GetStaticPaths } from "astro";
+import { getCollection } from "astro:content";
+import PortfolioItemLayout from "@/layouts/PortfolioItemLayout.astro";
export const getStaticPaths: GetStaticPaths = async () => {
const entries = await getCollection("portfolio");
@@ -17,50 +12,6 @@ export const getStaticPaths: GetStaticPaths = async () => {
};
const { entry } = Astro.props;
-const { Content } = await render(entry);
---
-<Layout title={entry.data.title} description={entry.data.description}>
- <a id="link-back" href="/portfolio">
- <svg
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 24 24"
- fill="none"
- stroke="currentColor"
- stroke-width="2"
- stroke-linecap="round"
- stroke-linejoin="round"
- class="w-6 h-6 inline-block mr-2"
- >
- <polyline points="15 18 9 12 15 6"></polyline>
- </svg>
- Volver al portfolio
- </a>
-
- <h1>{entry.data.title}</h1>
-
- <Content />
-
- <h2>Tecnologías utilizadas</h2>
-
- {
- entry.data.technologies.map((technology: string) => (
- <TechnologyBadge size="small" code={technology} />
- ))
- }
-</Layout>
-
-<style>
- a#link-back {
- display: inline-flex;
- align-items: center;
- gap: 0.5rem;
- text-decoration: none;
- text-transform: uppercase;
- transition: color 0.2s ease-in-out;
- }
-
- a#link-back svg {
- height: 1em;
- }
-</style>
+<PortfolioItemLayout entry={entry} />
diff --git a/src/pages/portfolio/index.astro b/src/pages/portfolio/index.astro
index 17c4637..f5f1250 100644
--- a/src/pages/portfolio/index.astro
+++ b/src/pages/portfolio/index.astro
@@ -1,5 +1,5 @@
---
-import PortfolioPageLayout from "../../layouts/PortfolioPageLayout.astro";
+import PortfolioPageLayout from "@/layouts/PortfolioPageLayout.astro";
---
<PortfolioPageLayout />