
El primer portfolio de Stelut
Este es el primer proyecto hecho con React, una aventura que marcó mi inicio en este ecosistema. A día de hoy, el proyecto ha evolucionado y se ha actualizado a las versiones más recientes de React para mantenerlo relevante y funcional. El código fuente está disponible en GitHub para quien quiera curiosear o aprender de él.
En sus inicios, la aplicación fue concebida como una página estática y se alojó en GitHub Pages. Aunque estática, React ya jugaba un papel, principalmente a nivel demostrativo, para gestionar la navegación entre las diferentes secciones del portfolio y para implementar una funcionalidad de cambio de idioma (español/inglés).
En esa primera etapa, los recursos como imágenes o datos de proyectos estaban integrados directamente en el código (‘hardcoded’), sin depender de CDNs externas o APIs, reflejando la simplicidad inicial del proyecto. Lo guardo con cariño como un archivo de mis primeros pasos.
Un aspecto interesante desde el principio fue su concepción como PWA (Progressive Web App), lo que permitía instalarla en dispositivos móviles o de escritorio para un acceso más directo, ofreciendo una experiencia más cercana a una aplicación nativa.
Stack y herramientas
-
React: usado de forma básica, sin router avanzado ni estado global.
-
Vite: en versiones posteriores, migré a Vite para mejorar la experiencia de desarrollo.
-
CSS puro: en lugar de utilizar Tailwind o frameworks, usé estilos básicos escritos a mano.
-
PWA: la app está lista para instalarse como aplicación nativa (Web App Manifest + Service Worker).
-
GitHub Pages: el sitio fue alojado originalmente en GitHub Pages por su naturaleza estática.
Funcionalidades y características
Navegación
Implementé un sistema de navegación SPA (Single Page Application) utilizando rutas hash (por ejemplo, #/home, #/about).
Multilenguaje
Permitía al usuario alternar entre español (es) e inglés (en), mostrando el contenido en el idioma de su preferencia. Usaba un contexto para cambiar de lenguaje:
import React, { createContext, useState, useEffect } from 'react';
export const LanguageContext = createContext();
export const LanguageProvider = ({ children }) => {
const browserLanguage = navigator.language || navigator.userLanguage;
const defaultLanguage = (browserLanguage.includes('es') || browserLanguage.includes('en'))
? browserLanguage.slice(0, 2)
: 'en';
const [language, setLanguage] = useState(defaultLanguage);
const [translations, setTranslations] = useState({});
const [isLoading, setLoading] = useState(true);
useEffect(() => {
setLoading(true);
fetch(`/local/${language}/translation.json`)
.then(response => response.json())
.then(data => {
setTimeout(() => {
setTranslations(data);
setLoading(false);
}, 150);
});
}, [language]);
return (
<LanguageContext.Provider value={{ language, setLanguage, translations, isLoading }}>
{!isLoading ? children : null}
</LanguageContext.Provider>
);
};
Más adelante lo envolvía en index.jsx
:
<LanguageProvider>
<App />
</LanguageProvider>
Y en el Navbar.jsx
simplemente hacía esto para cambiar de idioma:
const { language, setLanguage, translations } = useContext(LanguageContext);
const handleLanguageChange = (event) => {
setLanguage(event.target.value);
};
Los idiomas estaban precargados como recursos estáticos en públic, src/public/local/en/translation.json
y .../es/translation.json
respectivamente, allí tenía gran parte de la página.
Experiencia de usuario
El proyecto incluía varias animaciones suaves escritas en CSS puro, que mejoraban la interacción visual al hacer scroll o navegar entre secciones. El diseño intentaba ser adaptativo: sin ser completamente responsive, se cuidó que al menos en móviles la estructura no se rompiera, ajustándose de forma aceptable a pantallas más pequeñas.
Contacto
La forma de contacto era mediante número de teléfono/correo electrónico, además de había una librería para mandar formularios, formsubmit, implemenatado de eseta forma:
<form action="https://formsubmit.co/test" method="POST">
<div className="fields">
<div className="field name">
<input type="text" name="name" placeholder="Nombre" required />
</div>
<div className="field email">
<input type="email" name="email" placeholder="E-Mail" required />
</div>
</div>
<div className="field">
<input type="text" name="_subject" placeholder="Asunto" required />
</div>
<div className="field textarea">
<textarea cols="30" rows="10" name="message" placeholder="Describe el asunto..."
required></textarea>
</div>
<div className="button">
<button type="submit">Enviar mensaje</button>
</div>
</form>
Conclusión
Finalmente, todo el contenido estaba embebido directamente en el frontend. No existía una API, un CMS o backend. Las imágenes, textos y datos estaban ‘hardcoded’, lo que simplificaba el desarrollo inicial y lo hacía ideal para entender cómo construir un sitio estático con React.
Referencias
El código fuente está en github.
Otras librerías que intervienen/intervineieron:
- typed.js, para la animación de escritura.
- Formsubmit para mandar formularios.