summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAriel Costas Guerrero <ariel@costas.dev>2025-10-12 22:49:13 +0200
committerAriel Costas Guerrero <ariel@costas.dev>2025-10-12 22:49:13 +0200
commitcbdb2ee1547fcfbef8c874da60b17eee80b5fa18 (patch)
treef1adc98515c2ac7681dcd0902b9ebcc2997d6b73
parentdcc806eff41da24ee6b5984d011f62bc9f4f00ee (diff)
Get rid of trajectory and portfolio
-rw-r--r--public/fonts/robotoflex.woff2bin0 -> 747084 bytes
-rw-r--r--src/content.config.ts16
-rw-r--r--src/data/portfolio/mapa-ferrol.mdx45
-rw-r--r--src/data/portfolio/mientreno.mdx17
-rw-r--r--src/data/portfolio/order-extractor.mdx27
-rw-r--r--src/data/portfolio/qr-ponteareas.mdx13
-rw-r--r--src/data/portfolio/qr-touro.mdx13
-rw-r--r--src/data/portfolio/vigo-360.mdx17
-rw-r--r--src/data/portfolio/wp-consulting.mdx9
-rw-r--r--src/layouts/HomePageLayout.astro46
-rw-r--r--src/layouts/Layout.astro15
-rw-r--r--src/layouts/PortfolioListLayout.astro137
-rw-r--r--src/layouts/PortfolioSingleLayout.astro370
-rw-r--r--src/pages/contact.astro32
-rw-r--r--src/pages/portfolio/[id].astro17
-rw-r--r--src/pages/portfolio/index.astro5
-rw-r--r--src/pages/trajectory.astro5
-rw-r--r--src/partials/Header.astro5
-rw-r--r--styles/_variables.scss4
-rw-r--r--styles/shared.scss14
20 files changed, 37 insertions, 770 deletions
diff --git a/public/fonts/robotoflex.woff2 b/public/fonts/robotoflex.woff2
new file mode 100644
index 0000000..b4acfba
--- /dev/null
+++ b/public/fonts/robotoflex.woff2
Binary files differ
diff --git a/src/content.config.ts b/src/content.config.ts
index acaaf8a..b5fca4e 100644
--- a/src/content.config.ts
+++ b/src/content.config.ts
@@ -11,22 +11,6 @@ const blog = defineCollection({
}),
});
-const portfolio = defineCollection({
- loader: glob({ pattern: "**/*.{md,mdx}", base: "src/data/portfolio" }),
- schema: z.object({
- title: z.string(),
- description: z.string(),
- technologies: z.array(z.string()),
- githubLink: z.string().url().optional(),
- onlineLink: z.string().url().optional(),
- demoLink: z.string().url().optional(),
- images: z.array(
- z.object({ src: z.string(), alt: z.string() })
- ).default([])
- }),
-});
-
export const collections = {
blog,
- portfolio,
};
diff --git a/src/data/portfolio/mapa-ferrol.mdx b/src/data/portfolio/mapa-ferrol.mdx
deleted file mode 100644
index 6152ced..0000000
--- a/src/data/portfolio/mapa-ferrol.mdx
+++ /dev/null
@@ -1,45 +0,0 @@
----
-title: "Mapa de patrimonio da Costa Ártabra"
-description: "Desarrollo de una aplicación completa para el patrimonio cultural y militar de la Costa Ártabra."
-technologies: ["dotnet", "react", "mysql", "ubuntu"]
-onlineLink: "https://mapacostaartabramilitar.com"
-images:
-- src: "/images/portfolio/mapa-ferrol/home-narrow"
- alt: "Vista principal del mapa con los elementos del patrimonio"
-- src: "/images/portfolio/mapa-ferrol/home-info-narrow"
- alt: "Sheet con información de un elemento patrimonial"
-- src: "/images/portfolio/mapa-ferrol/route-id-narrow"
- alt: "Vista de una ruta predefinida"
-- src: "/images/portfolio/mapa-ferrol/planner-narrow"
- alt: "Planificador de rutas de senderismo"
----
-
-Desarrollo de una **aplicación web integral** para la exploración del patrimonio cultural y militar de la Costa Ártabra (Ferrol, Ares, Valdoviño). La plataforma incluye baterías costeras, faros, rutas de senderismo y puntos de interés natural, ofreciendo una experiencia adaptada principalmente a dispositivos móviles.
-
-Tecnologías clave:
-
-* Backend con ASP.NET Core y base de datos MySQL.
-* Frontend en React (TypeScript) y mapas interactivos con MapLibre.
-* Teselas vectoriales de OpenStreetMap con [Protomaps](https://protomaps.com/) para un mapa de alta calidad y buen rendimiento.
-* Calculador de rutas autoalojado con [OSRM](https://project-osrm.org/) para optimización de rutas.
-
-Diseñada para autonomía y privacidad:
-
-* Infraestructura autoalojada (Ubuntu) sin dependencia de APIs comerciales.
-* Optimización de rutas con motor de cálculo interno (OSRM).
-* Panel de administración para gestión centralizada del patrimonio.
-
-## Características clave
-
-1. **Tecnologías autónomas**: Implementación sin dependencia de servicios externos (como Google Maps), garantizando privacidad del usuario y reducción de costos.
-
-2. **Gestión de recursos**: Solución personalizada para iconografía y capas de mapa, asegurando consistencia visual y eficiencia.
-
-3. **Planificación de rutas inteligente**: Sistema de optimización para senderismo basado en puntos patrimoniales, con énfasis en rendimiento y estabilidad.
-
-4. **Panel de administración**: Herramienta interna para gestión de contenido por personal no técnico.
-
-
----
-
-Desarrollado en 2025 en colaboración con [Kendra](https://kendra.es/).
diff --git a/src/data/portfolio/mientreno.mdx b/src/data/portfolio/mientreno.mdx
deleted file mode 100644
index 79a40c6..0000000
--- a/src/data/portfolio/mientreno.mdx
+++ /dev/null
@@ -1,17 +0,0 @@
----
-title: "MiEntreno"
-description: "Creación de un sitio web dinámico con PHP adaptado a móviles y accesible mediante QR en localizaciones físicas"
-technologies: ["dotnet", "azure"]
----
-
-Aplicación web para la gestión de entrenamientos deportivos, con una interfaz sencilla y fácil de usar. Desarrollado con ASP.NET Core, Razor Pages y SQL Server, y alojada en Azure App Service.
-
-La aplicación permite a los entrenadores personales crear y gestionar rutinas de entrenamiento para sus clientes, que pueden proporcionar _feedback_ sobre estos. Además, los clientes pueden ver sus rutinas de entrenamiento y registrar sus progresos en la aplicación.
-
-La principal complejidad que me encontré en este proyecto fue la implementación de los dos roles de usuario (entrenador y cliente) y la gestión de los permisos de acceso a las distintas partes de la aplicación, con filtrado para evitar mostrar datos potencialmente sensibles.
-
-Además, el tiempo de desarrollo era muy limitado, al tratarse del proyecto final de ciclo, en un plazo de 3 meses desde la concepción de la idea, redacción del proyecto y desarrollo de la aplicación. Podría considerarse un _MVP_ (Producto Mínimo Viable) de la idea original, con muchas funcionalidades que quedaron fuera del alcance de este proyecto.
-
-También, fue un "campo de pruebas" para mí, ya que fue el primer proyecto serio que desarrollé con ASP.NET Core, y donde también quise introducir el uso de emailing transaccional, colas de mensajes y otros conceptos más avanzados que no había utilizado antes en una aplicación real.
-
-El código fuente se puede encontrar en [GitHub](https://github.com/arielcostas/mientreno) bajo la licencia GNU Affero GPL v3.0.
diff --git a/src/data/portfolio/order-extractor.mdx b/src/data/portfolio/order-extractor.mdx
deleted file mode 100644
index dfdbd2e..0000000
--- a/src/data/portfolio/order-extractor.mdx
+++ /dev/null
@@ -1,27 +0,0 @@
----
-title: "Extractor de pedidos (2023-actualidad)"
-description: "Extractor de pedidos de compra online para generar informes de ventas y rentabilidad"
-technologies: ["java", "windows"]
----
-
-Implementación de una aplicación de escritorio que extrae los datos sobre los pedidos on-line
-de diversas plataformas (como WooCommerce, Amazon y Ebay) para almacenar de forma local y
-centralizada. Además, cruza estos datos con la base de datos de productos en almacén y sus
-precios de coste, para generar informes de Excel sobre los ingresos y costes por cada pedido,
-así como calcular la rentabilidad de estos.
-
-Los principales problemas enfrentados en este proyecto fueron la diversidad de formatos de los
-datos de entrada y la necesidad de mantener la aplicación actualizada con los cambios en las
-plataformas de venta online; además de no contar con SDKs oficiales para estas plataformas,
-teniendo que implementar llamadas HTTP a las API públicas, a veces con autenticación compleja
-o firma de peticiones (como AWS Signature V4).
-
-Por otra parte, está la distribución, instalación y actualización de la aplicación en los
-equipos del cliente, teniendo que generar un instalador MSI firmado a partir del Java compilado
-y _shaded_ con sus dependencias mediante maven, y `jpackage` para generar el ejecutable nativo
-de Windows.
-
-Trabajo inicial realizado en 2023 para un cliente de España, con mantenimiento hasta la actualidad.
-En 2025 se comenzó un proyecto de migración a una aplicación cloud con más funcionalidades y que
-soluciona dificultades como la sincronización de datos entre equipos y la generación de nuevos tipos
-de informes.
diff --git a/src/data/portfolio/qr-ponteareas.mdx b/src/data/portfolio/qr-ponteareas.mdx
deleted file mode 100644
index 61449f3..0000000
--- a/src/data/portfolio/qr-ponteareas.mdx
+++ /dev/null
@@ -1,13 +0,0 @@
----
-title: "Museo a ceo aberto de Ponteareas"
-description: "Creación de un sitio web dinámico con PHP adaptado a móviles y accesible mediante QR en localizaciones físicas"
-technologies: ["php", "web"]
-demoLink: "https://museocorpus.ponteareas.gal/?place=01-bugallal"
----
-
-Creación de un sitio web dinámico con PHP adaptado a móviles y accesible mediante
-QR en localizaciones físicas. Cada página muestra datos de la ubicación correspondiente
-en tres idiomas (castellano, gallego e inglés), una galería de imágenes en 360º con
-la biblioteca PanoLens y vídeos incrustados de YouTube.
-
-Desarrollado en 2021 en colaboración con [Kendra](https://kendra.es/).
diff --git a/src/data/portfolio/qr-touro.mdx b/src/data/portfolio/qr-touro.mdx
deleted file mode 100644
index 63a770e..0000000
--- a/src/data/portfolio/qr-touro.mdx
+++ /dev/null
@@ -1,13 +0,0 @@
----
-title: "Punto de información turística en móviles"
-description: "Creación de un sitio web dinámico con PHP adaptado a móviles y accesible mediante QR en localizaciones físicas"
-technologies: ["typescript", "web"]
-demoLink: "https://www.concellodetouro.com/qr-carteis/petroglifo.html"
----
-
-Desarrollo de un generador estático en TypeScript para información turística del Concello de
-Touro, A Coruña, con un sitio web dinámico adaptado a móviles. El sitio se accede mediante códigos QR
-en localizaciones físicas, permitiendo a los usuarios obtener información sobre el patrimonio cultural
-y natural de la zona.
-
-Desasrrollado en 2020, en colaboración con [Kendra](https://kendra.es/).
diff --git a/src/data/portfolio/vigo-360.mdx b/src/data/portfolio/vigo-360.mdx
deleted file mode 100644
index 2bebdf3..0000000
--- a/src/data/portfolio/vigo-360.mdx
+++ /dev/null
@@ -1,17 +0,0 @@
----
-title: "Vigo 360"
-description: "Desarrollo y publicación de un blog sobre Vigo"
-technologies: ["go", "mysql", "ubuntu"]
-onlineLink: "https://vigo360.es"
-githubLink: "https://github.com/arielcostas/vigo360"
----
-
-Blog sobre Vigo y su entorno, orientado principalmente a hablar de movilidad y toponimia. Desarrollado en Go, con base de datos MySQL y desplegado sobre infraestructura propia.
-
-Opté por desarrollarlo de cero, en lugar de invertir mis esfuerzos en aprender a desarrollar sobre WordPress, por la necesidad de mantener una tonelada de plugins, un tema propio y código que no controlaba. Además, me permitió aprender Go y desplegar una aplicación en producción.
-
-Además de esto, ocasionalmente publico contenido en este blog sobre transporte público, movilidad y toponimia en Vigo y su entorno; sin fines de lucro y con un nivel de rigor que nos ha llevado a ser citados en medios de comunicación locales como un medio especializado en estos temas.
-
-El blog cuenta con un sistema publicaciones, comentarios, etiquetas y búsqueda (con Algolia), así como optimización para buscadores y redes sociales con etiquetas de OpenGraph, Twitter Cards y datos semánticos de Schema.org mediante JSON-LD.
-
-Durante 2025 se planea hacer una reescritura de la aplicación usando .NET para poder implementar nuevas funcionalidades, como procesamiento de fondo de ciertas tareas (generar miniaturas, indexar contenido, etc.) y mejorar la manteniabilidad del código, o búsqueda mediante vectores sin depender de terceros.
diff --git a/src/data/portfolio/wp-consulting.mdx b/src/data/portfolio/wp-consulting.mdx
deleted file mode 100644
index 0b6a35f..0000000
--- a/src/data/portfolio/wp-consulting.mdx
+++ /dev/null
@@ -1,9 +0,0 @@
----
-title: "Consultoría WordPress"
-description: "Trabajos de mantenimiento, optimización y migración de sitios web WordPress y tiendas online WooCommerce"
-technologies: ["php"]
----
-
-Trabajos de mantenimiento, optimización y migración de sitios web WordPress y tiendas online WooCommerce. Incluyendo la instalación y configuración de plugins, temas y optimización de rendimiento y SEO.
-
-Trabajo bajo la premisa de reducir la dependencia de plugins y temas de terceros, y de mejorar la seguridad y rendimiento de los sitios web; además de usar herramientas optimizadas y sin limitaciones artificiales bajo muros de pago, en la medida de lo posible.
diff --git a/src/layouts/HomePageLayout.astro b/src/layouts/HomePageLayout.astro
index fb3cf34..ca009a5 100644
--- a/src/layouts/HomePageLayout.astro
+++ b/src/layouts/HomePageLayout.astro
@@ -24,56 +24,12 @@ const schema = {
/>
<h1>Inicio</h1>
+
<p>
Te doy la bienvenida a mi web. Me llamo Ariel, y aquí encontrarás
información sobre mí y mis proyectos.
</p>
- <h2>¿Quién soy?</h2>
-
- <p>
- Soy un desarrollador de software con varios años de experiencia en el
- sector, especializado en el desarrollo de aplicaciones web y la
- administración de sistemas Cloud. Me apasiona la tecnología y disfruto
- creando soluciones prácticas y eficientes para resolver problemas reales,
- simplificando la vida y el trabajo de las personas.
- </p>
-
- <p>
- En mi tiempo libre, fuera de mi trabajo, me interesan temas como la
- filosofía, la economía y las finanzas, así como el derecho y la política. Me
- gusta aprender sobre cómo funcionan las cosas y cómo se relacionan entre sí,
- y reflexionar sobre el impacto que tienen en nuestra sociedad y en nuestras
- vidas cotidianas.
- </p>
-
- <h2>¿Qué hago?</h2>
-
- <p>
- Actualmente trabajo como desarrollador de software y administrador Cloud en
- Estelaria Solutions, una empresa de tecnología en Vigo (España). Me encargo
- de desarrollar aplicaciones web en PHP y desplegarlas en la nube de forma
- segura y eficiente.
- </p>
-
- <a href="/trajectory/">Conoce más sobre mi trayectoria profesional</a>
-
- <p>
- También realizo ocasinalmente proyectos personales y freelance para clientes
- que necesitan soluciones a medida o apoyo técnico en sus proyectos. Me gusta
- trabajar con tecnologías modernas y aprender nuevas habilidades para mejorar
- mi trabajo y ofrecer un mejor servicio a mis clientes.
- </p>
-
- <p>
- Si necesitas ayuda con un proyecto o quieres colaborar conmigo, no dudes en
- ponerte en contacto conmigo a través de mi correo electrónico o mis redes
- sociales.
- </p>
-
- <a href="/portfolio/">Echa un vistazo a mi portfolio</a>
-
- <h2>Mis reflexiones</h2>
<p>
En mi blog comparto mis reflexiones, aprendizajes y experiencias sobre los
temas que me interesan, además de hablar ocasionalmente sobre tecnología y
diff --git a/src/layouts/Layout.astro b/src/layouts/Layout.astro
index 6e389e2..3aa2dd0 100644
--- a/src/layouts/Layout.astro
+++ b/src/layouts/Layout.astro
@@ -1,6 +1,4 @@
---
-import "@fontsource-variable/roboto";
-import "@fontsource-variable/roboto-mono";
import Header from "../partials/Header.astro";
import Footer from "../partials/Footer.astro";
@@ -137,8 +135,19 @@ const { title, description, empty } = Astro.props;
background-color: color.adjust($accent, $alpha: -0.85);
}
+ ul:has(li) {
+ padding-left: 1.25rem;
+ margin-top: 0;
+ margin-bottom: 1.5rem;
+
+ display: flex;
+ flex-direction: column;
+ gap: 0.5rem;
+ }
+
li > time {
- font-family: $monoFontStack;
+ font-size: 0.95rem;
+ user-select: none;
}
main {
diff --git a/src/layouts/PortfolioListLayout.astro b/src/layouts/PortfolioListLayout.astro
deleted file mode 100644
index b509bec..0000000
--- a/src/layouts/PortfolioListLayout.astro
+++ /dev/null
@@ -1,137 +0,0 @@
----
-import t from "../i18n/es.json";
-
-import Layout from "./Layout.astro";
-import PortfolioProject from "@/components/PortfolioProject.astro";
-
-const schema = {
- "@context": "https://schema.org",
- "@type": "WebPage",
- url: "https://www.costas.dev/portfolio",
- headline: t.portfolioPage.headline,
-};
----
-
-<Layout title={t.portfolioPage.title} description={t.portfolioPage.description}>
- <script
- is:inline
- type="application/ld+json"
- slot="head-jsonld"
- set:html={JSON.stringify(schema)}
- />
-
- <h1>{t.portfolioPage.headline}</h1>
-
- <p set:html={t.portfolioPage.intro} />
-
- <h2>{t.portfolioPage.freelanceTitle}</h2>
-
- <p>{t.portfolioPage.freelanceDesc}</p>
-
- <section>
- <PortfolioProject
- title="Mapa patrimonial de la Costa Ártabra"
- summary="Desarrollo de una aplicación completa para el patrimonio cultural y militar de la Costa Ártabra, con un sistema CMS para el personal de la administración y una aplicación web progresiva (PWA) para visualizar el mapa y planificar rutas."
- tags={["dotnet", "react", "mysql", "ubuntu"]}
- detailsLink="/portfolio/mapa-ferrol/"
- onlineLink="https://mapacostaartabramilitar.com"
- />
-
- <PortfolioProject
- title="Extractor de pedidos venta online"
- summary="Aplicación de escritorio que extrae los datos sobre los pedidos on-line de diversas plataformas (como WooCommerce, Amazon y Ebay)."
- tags={["java", "windows"]}
- detailsLink="/portfolio/order-extractor/"
- />
-
- <PortfolioProject
- title="Museo a ceo aberto de Ponteareas"
- summary="Desarrollo de visualización de contenido turístico para el Concello de Ponteareas. Incluye contenido en 360º e incrustación de vídeos de YouTube. Realizado en 2021."
- tags={["php", "web"]}
- detailsLink="/portfolio/qr-ponteareas/"
- />
-
- <PortfolioProject
- title="QR Touro turístico"
- summary="Desarrollo de un generador estático en TypeScript para información turística del Concello de Touro. Realizado en 2020."
- tags={["typescript", "web"]}
- detailsLink="/portfolio/qr-touro/"
- />
-
- <PortfolioProject
- title="Consultoría WordPress"
- summary="Trabajos de mantenimiento, optimización y migración de sitios web WordPress y tiendas online WooCommerce."
- tags={["php", "wordpress"]}
- detailsLink="/portfolio/wp-consulting/"
- />
- </section>
-
- <h2>{t.portfolioPage.ownProjectsTitle}</h2>
-
- <p>{t.portfolioPage.ownProjectsDesc}</p>
-
- <section>
- <PortfolioProject
- title="Web personal"
- summary="Desarrollado con Astro, un generador de sitios web estáticos que permite escribir contenido en Markdown y publicar en la web con un rendimiento excelente. Desplegado via GitHub Actions en mi servidor."
- tags={["astro", "github", "ubuntu"]}
- githubLink="https://github.com/arielcostas/costasdev"
- />
-
- <PortfolioProject
- title="MiEntreno (proyecto fin de ciclo)"
- summary="Aplicación web para la gestión de entrenamientos deportivos, con una interfaz sencilla y fácil de usar. Desarrollado con ASP.NET Core, Razor Pages y SQL Server."
- tags={["dotnet", "azure"]}
- githubLink="https://github.com/arielcostas/mientreno"
- detailsLink="/portfolio/mientreno/"
- />
-
- <PortfolioProject
- title="Vigo 360"
- summary="Blog sobre Vigo y su entorno, orientado principalmente a hablar de movilidad y toponimia. Desarrollado en Go, con base de datos MySQL y desplegado sobre VPS administrado por mí mismo."
- tags={["go", "mysql", "ubuntu"]}
- githubLink="https://github.com/arielcostas/vigo360"
- detailsLink="/portfolio/vigo-360/"
- onlineLink="https://vigo360.es"
- />
- </section>
-
- <div class="trajectory-summary">
- <h2>{t.portfolioPage.trajectoryTitle}</h2>
- <p>{t.portfolioPage.trajectorySummary}</p>
- <a href="/trajectory" class="cta-link">{t.portfolioPage.viewTrajectory} →</a>
- </div>
-</Layout>
-
-<style>
- section {
- display: grid;
- grid-template-columns: repeat(auto-fill,minmax(350px,1fr));
- gap: 1.5rem;
- }
-
- .trajectory-summary {
- margin-top: 3rem;
- background-color: #FFFFFF;
- border-radius: 8px;
- padding: 1.5rem;
- box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.08);
- border-left: 4px solid hsl(209, 94%, 42%);
- }
-
- .trajectory-summary h2 {
- margin-top: 0;
- }
-
- .cta-link {
- display: inline-block;
- margin-top: 0.5rem;
- font-weight: 600;
- text-decoration: none;
- color: hsl(215, 90%, 30%);
- }
-
- .cta-link:hover {
- text-decoration: underline;
- }
-</style>
diff --git a/src/layouts/PortfolioSingleLayout.astro b/src/layouts/PortfolioSingleLayout.astro
deleted file mode 100644
index 1922e16..0000000
--- a/src/layouts/PortfolioSingleLayout.astro
+++ /dev/null
@@ -1,370 +0,0 @@
----
-import Layout from "@/layouts/Layout.astro";
-import { render } from "astro:content";
-import TechnologyBadge from "@/components/TechnologyBadge.astro";
-import type { InferEntrySchema } from "astro:content";
-import { Icon } from "astro-icon/components";
-
-interface Props {
- entry: any;
-}
-
-const { entry } = Astro.props;
-const data = entry.data as InferEntrySchema<"portfolio">;
-const { Content } = await render(entry);
----
-
-<Layout title={data.title} description={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>{data.title}</h1>
-
- <small>Hecho con {data.technologies.map((technology: string) => (
- <TechnologyBadge size="small" code={technology} />
- ))}</small>
-
- <Content />
-
- <div class="project-links">
- {data.githubLink && <a href={data.githubLink} target="_blank" rel="noopener noreferrer" class="project-link">
- <Icon name="tabler:brand-github" class="link-icon"/>
- <span>Código en GitHub</span>
- </a>}
-
- {data.onlineLink && <a href={data.onlineLink} target="_blank" rel="noopener noreferrer" class="project-link">
- <Icon name="tabler:external-link" class="link-icon"/>
- <span>Ver en línea</span>
- </a>}
-
- {data.demoLink && <a href={data.demoLink} target="_blank" rel="noopener noreferrer" class="project-link">
- <Icon name="tabler:device-laptop" class="link-icon"/>
- <span>Ver demo</span>
- </a>}
- </div>
-
- {data.images.length > 0 && (
- <h2>Galería</h2>
- <section id="project-images">
- {data.images.map((image) => (
- <a href={`${image.src}.png`} target="_blank" rel="noopener noreferrer">
- <picture>
- <source
- srcset={`${image.src}.webp`}
- type="image/webp"
- />
- <img src={`${image.src}.png`} alt={image.alt} loading="lazy" />
- </picture>
- </a>
- ))}
- </section>
- )}
-
- <dialog id="largeimage-dialog">
- <div id="largeimage-dialogcontainer">
- <button class="largeimage__nav" aria-label="Previous image" id="largeimage__nav-left">
- <Icon name="tabler:chevron-left" />
- </button>
- <div id="largeimage-imagecontainer">
- <img id="largeimage-image" alt="Some alt" />
- </div>
- <div id="largeimage-caption">Some caption</div>
- <button class="largeimage__nav" aria-label="Next image" id="largeimage__nav-right">
- <Icon name="tabler:chevron-right" />
- </button>
- <button id="largeimage-close"><Icon name="tabler:x" /></button>
- </div>
- </dialog>
-
-</Layout>
-
-<script>
- document.addEventListener("DOMContentLoaded", () => {
- const dialog = document.getElementById("largeimage-dialog") as HTMLDialogElement;
- const closeButton = document.getElementById("largeimage-close") as HTMLButtonElement;
- const imageElement = document.getElementById("largeimage-image") as HTMLImageElement;
- const captionElement = document.getElementById("largeimage-caption") as HTMLDivElement;
- const navLeft = document.getElementById("largeimage__nav-left") as HTMLButtonElement;
- const navRight = document.getElementById("largeimage__nav-right") as HTMLButtonElement;
- const imageLinks = Array.from(document.querySelectorAll("#project-images a")) as HTMLAnchorElement[];
-
- const images = imageLinks.map(link => {
- const img = link.querySelector("img");
- return {
- src: img?.src,
- alt: img?.alt
- };
- });
- let currentIndex = 0;
-
- function showImage(index: number) {
- if (index < 0 || index >= images.length) return;
- currentIndex = index;
- const { src, alt } = images[currentIndex];
- if (!imageElement || !captionElement) {
- console.error("Image or caption element not found");
- return;
- }
- imageElement.src = src!;
- imageElement.alt = alt!;
- captionElement.textContent = alt || "Imagen del proyecto";
- }
-
- if (!dialog || !closeButton || !imageElement || !captionElement) {
- console.error("Dialog or elements not found");
- return;
- }
-
- imageLinks.forEach((link, idx) => {
- link.addEventListener("click", (e) => {
- e.preventDefault();
- showImage(idx);
- dialog.showModal();
- });
- });
-
- closeButton.addEventListener("click", () => {
- dialog.close();
- });
-
- if (navLeft) {
- navLeft.addEventListener("click", (e) => {
- e.preventDefault();
- showImage((currentIndex - 1 + images.length) % images.length);
- });
- }
- if (navRight) {
- navRight.addEventListener("click", (e) => {
- e.preventDefault();
- showImage((currentIndex + 1) % images.length);
- });
- }
-
- dialog.addEventListener("keydown", (e) => {
- if (e.key === "ArrowLeft") {
- showImage((currentIndex - 1 + images.length) % images.length);
- } else if (e.key === "ArrowRight") {
- showImage((currentIndex + 1) % images.length);
- } else if (e.key === "Escape") {
- dialog.close();
- }
- });
-
- dialog.addEventListener("shown", () => {
- dialog.focus();
- });
-
- dialog.addEventListener("open", () => {
- dialog.focus();
- });
-
- dialog.addEventListener("click", (e) => {
- if (e.target === dialog) {
- dialog.close();
- }
- });
- });
-</script>
-
-<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;
- }
-
- #project-images {
- display: flex;
- flex-direction: row;
- gap: 1.5rem;
- margin: 1.5rem 0 2rem;
- overflow-x: auto;
- padding-bottom: 1rem;
- -webkit-overflow-scrolling: touch;
- scrollbar-width: thin;
- }
-
- #project-images a {
- display: block;
- flex: 0 0 auto;
- box-shadow: none;
- text-decoration: none;
- padding: 0;
- }
-
- #project-images picture {
- display: block;
- overflow: hidden;
- border-radius: 0.25rem;
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
- height: max(20vh, 400px);
- }
-
- #project-images img {
- height: 100%;
- object-fit: cover;
- }
-
- #project-images a {
- position: relative;
- }
-
- .project-links {
- display: flex;
- gap: 1rem;
- flex-wrap: wrap;
- margin: 1.5rem 0 2.5rem;
- }
-
- .project-link {
- display: inline-flex;
- align-items: center;
- gap: 0.5rem;
- padding: 0.5rem 1.25rem;
- border-radius: 2rem;
- background-color: #f3f4f6;
- color: #333;
- font-weight: 600;
- text-decoration: none;
- box-shadow: none;
- transition: all 0.2s ease-in-out;
-
- &:hover {
- background-color: #e5e7eb;
- transform: translateY(-2px);
- box-shadow: none;
- }
-
- &:focus {
- outline: 2px solid $secondary;
- background-color: #e5e7eb;
- box-shadow: none;
- }
-
- .link-icon {
- font-size: 1.2rem;
- }
- }
-
- #largeimage-dialog {
- padding: 0;
- border: none;
- background: transparent;
- max-width: 100vw;
- max-height: 100vh;
- margin: auto;
- }
-
- #largeimage-dialog::backdrop {
- background: #000c;
- }
-
- #largeimage-dialogcontainer {
- position: relative;
- display: flex;
- flex-direction: column;
- gap: 1rem;
- height: 100%;
- padding: 1.5rem;
- }
-
- #largeimage-imagecontainer {
- max-width: 100%;
- max-height: calc(100vh - 2rem);
- overflow: hidden;
- position: relative;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- }
-
- #largeimage-image {
- object-fit: cover;
- max-width: 100%;
- max-height: calc(100vh - 9rem);
-
- border-radius: 0.5rem;
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
- }
-
- #largeimage-caption {
- position: static;
- background: #FFFC;
- color: #000;
- font-size: 1rem;
- text-align: center;
- border-radius: 0.5rem;
- padding: 0.75rem 1rem;
- max-width: 100%;
- }
-
- #largeimage-close {
- position: absolute;
- top: 1rem;
- right: 1rem;
- width: 2rem;
- height: 2rem;
- border: none;
- background: #fffc;
- border-radius: 50%;
- cursor: pointer;
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 1.5rem;
- color: #000;
- transition: background-color .2s;
- }
-
- .largeimage__nav {
- position: absolute;
- top: 50%;
- transform: translateY(-50%);
- width: 2.5rem;
- height: 2.5rem;
- border: none;
- background: #fffc;
- border-radius: 50%;
- cursor: pointer;
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 2rem;
- z-index: 2;
- color: #000;
- transition: background-color .2s;
- }
-
- #largeimage__nav-left {
- left: 1rem;
- }
- #largeimage__nav-right {
- right: 1rem;
- }
-
- .largeimage__nav:hover,
- #largeimage-close:hover {
- background-color: #FFFFFF;
- }
-</style>
diff --git a/src/pages/contact.astro b/src/pages/contact.astro
index 9cb58a6..bd5984e 100644
--- a/src/pages/contact.astro
+++ b/src/pages/contact.astro
@@ -25,51 +25,31 @@ const schema = {
<p>
La forma más sencilla de contactar conmigo es a través de mi dirección de
correo electrónico:
- <a href="#" id="email-addr">ACTIVA JAVASCRIPT PARA VER ESTO</a>. También
- puedes usar <a href="https://wa.me/message/W7T7L4EZAELQI1">WhatsApp</a> con el
- número de teléfono
- <a href="#" id="phone-number">ACTIVA JAVASCRIPT PARA VER ESTO</a>.
+ <a href="#" id="email-addr">ACTIVA JAVASCRIPT PARA VER ESTO</a>.
</p>
- <p>También puedes encontrarme en algunas redes sociales:</p>
-
- <dl>
- <dt>GitHub</dt>
- <dd><a href="https://github.com/arielcostas">@arielcostas</a></dd>
- <dt>LinkedIn</dt>
- <dd>
- <a href="https://www.linkedin.com/in/ariel-costas/">/in/ariel-costas</a>
- </dd>
- <dt>BlueSky</dt>
- <dd><a href="https://bsky.app/profile/costas.dev">@costas.dev</a></dd>
- </dl>
+ <p>
+ También puedes encontrarme en GitHub:
+ <a href="https://github.com/arielcostas">@arielcostas</a>
+ </p>
</Layout>
<script>
const encryptedEmail = "LygNLiMmFRo/GlQZaFIWBA==";
- const encryptedPhoneNumber = "ZWlQfX1QT0Z+XgVd";
const key = "NZdKOfvuLn5jF6sryF0Q";
const emailAddrLink = document.getElementById(
"email-addr",
) as HTMLAnchorElement;
- const phoneNumberLink = document.getElementById(
- "phone-number",
- ) as HTMLAnchorElement;
-
(() => {
- if (emailAddrLink == null || phoneNumberLink == null) {
+ if (emailAddrLink == null) {
return;
}
const emailAddress = xorData(encryptedEmail, key);
- const phoneNumber = xorData(encryptedPhoneNumber, key);
emailAddrLink.href = `mailto:${emailAddress}`;
emailAddrLink.textContent = emailAddress;
-
- phoneNumberLink.href = `tel:${phoneNumber}`;
- phoneNumberLink.textContent = phoneNumber;
})();
function xorData(data: string, key: string): string {
diff --git a/src/pages/portfolio/[id].astro b/src/pages/portfolio/[id].astro
deleted file mode 100644
index 7424b91..0000000
--- a/src/pages/portfolio/[id].astro
+++ /dev/null
@@ -1,17 +0,0 @@
----
-import type { GetStaticPaths } from "astro";
-import { getCollection } from "astro:content";
-import PortfolioSingleLayout from "@/layouts/PortfolioSingleLayout.astro";
-
-export const getStaticPaths: GetStaticPaths = async () => {
- const entries = await getCollection("portfolio");
- return entries.map((entry: any) => ({
- params: { id: entry.id },
- props: { entry },
- }));
-};
-
-const { entry } = Astro.props;
----
-
-<PortfolioSingleLayout entry={entry} />
diff --git a/src/pages/portfolio/index.astro b/src/pages/portfolio/index.astro
deleted file mode 100644
index c12ab23..0000000
--- a/src/pages/portfolio/index.astro
+++ /dev/null
@@ -1,5 +0,0 @@
----
-import PortfolioListLayout from "@/layouts/PortfolioListLayout.astro";
----
-
-<PortfolioListLayout />
diff --git a/src/pages/trajectory.astro b/src/pages/trajectory.astro
deleted file mode 100644
index b1366e6..0000000
--- a/src/pages/trajectory.astro
+++ /dev/null
@@ -1,5 +0,0 @@
----
-import TrajectoryPageLayout from "../layouts/TrajectoryPageLayout.astro";
----
-
-<TrajectoryPageLayout />
diff --git a/src/partials/Header.astro b/src/partials/Header.astro
index e8db9d5..5fc8010 100644
--- a/src/partials/Header.astro
+++ b/src/partials/Header.astro
@@ -17,8 +17,6 @@ import t from "../i18n/es.json";
<nav class="nav-links" id="nav-links" aria-label="Main navigation">
<a href="/">{t.header.home}</a>
- <a href="/trajectory/">{t.header.trajectory}</a>
- <a href="/portfolio/">{t.header.portfolio}</a>
<a href="/blog/">{t.header.blog}</a>
<a href="/contact/">{t.header.contact}</a>
</nav>
@@ -83,7 +81,8 @@ import t from "../i18n/es.json";
.brand-link {
font-size: 1.8rem;
- font-weight: 800;
+ font-weight: 700;
+ font-variation-settings: "wdth" 87.5,"wght" 700,"GRAD" 150;
text-decoration: none;
color: $accent;
diff --git a/styles/_variables.scss b/styles/_variables.scss
index 2defb13..0678cd4 100644
--- a/styles/_variables.scss
+++ b/styles/_variables.scss
@@ -1,5 +1,5 @@
-$titleFontStack: "Roboto Variable", system-ui, "Liberation Sans", "Arial", "Helvetica", sans-serif;
-$mainFontStack: "Roboto Variable", system-ui, "Liberation Sans", "Arial", "Helvetica", sans-serif;
+$titleFontStack: "Roboto Flex", system-ui, "Liberation Sans", "Arial", "Helvetica", sans-serif;
+$mainFontStack: "Roboto Flex", system-ui, "Liberation Sans", "Arial", "Helvetica", sans-serif;
$monoFontStack: "Roboto Mono Variable", "Fira Code", "Consolas", monospace;
$accent: hsl(209, 94%, 42%);
diff --git a/styles/shared.scss b/styles/shared.scss
index 053350f..ef9379c 100644
--- a/styles/shared.scss
+++ b/styles/shared.scss
@@ -1,6 +1,14 @@
@use "./variables" as *;
@use "./alert";
+@font-face {
+ font-display: swap;
+ font-family: 'Roboto Flex';
+ font-style: normal;
+ font-weight: 100 900;
+ src: url('/fonts/robotoflex.woff2') format('woff2');
+}
+
body {
font-family: $mainFontStack;
line-height: 1.65;
@@ -17,12 +25,14 @@ h1 {
@extend %heading;
font-size: 3.25rem;
line-height: 1.3;
+
}
h2 {
@extend %heading;
font-size: 2.5rem;
line-height: 1.55;
+ font-variation-settings: "wdth" 87.5,"wght" 700,"GRAD" 150
}
h3 {
@@ -36,3 +46,7 @@ h4 {
font-size: 1.25rem;
line-height: 1.55;
}
+
+p {
+ font-variation-settings: "GRAD" -15,"wdth" 112.5;
+}