Este es mi portafolio como desarrollador fullstack, donde muestro proyectos destacados que abarcan desde frontend interactivo hasta backend con microservicios. La interfaz está inspirada en el estilo visual de rauno.me, con un diseño tipo masonry, animaciones suaves y efectos visuales minimalistas.
- React 19 – para el frontend dinámico
- Next.js – framework React para aplicaciones fullstack (App Router)
- TailwindCSS – para el estilo moderno y responsivo
- React Masonry – para el layout tipo masonry
- React Router – para navegación SPA
- MDX – para contenido dinámico de ensayos
- Vite – para el entorno de desarrollo ultrarrápido
- Lucide React – para iconografía moderna
- Context API – para gestión de estado global (idiomas, tema)
- EmailJS – para formularios de contacto
/src
├─ /components
│ ├─ /prototypes # Componentes de prototipos interactivos
│ │ ├─ CustomCursor.jsx
│ │ ├─ DarkModeToggle.jsx
│ │ ├─ GooeyTooltip.jsx
│ │ ├─ PillNavBarDarkDock.jsx
│ │ ├─ PlaygroundCard.jsx
│ │ ├─ Sidebar.jsx
│ │ ├─ TodoBasic.jsx
│ │ └─ VanishInput.jsx
│ ├─ PrototypeLayout.jsx # Layout común para prototipos
│ ├─ DarkModeToggle.jsx # Toggle de modo oscuro
│ ├─ ProyectoCard.jsx # Tarjetas de proyectos
│ ├─ PrevNext.jsx # Navegación entre páginas
│ ├─ EssayImage.jsx # Componente para imágenes en ensayos
│ ├─ WebPreview.jsx # Preview de sitios web en ensayos
│ ├─ CodeBlock.jsx # Bloque de código con botón copiar
│ └─ EditableCode.jsx # Editor de código con preview en vivo
├─ /pages
│ ├─ Home.jsx # Página principal con masonry
│ ├─ PrototypePage.jsx # Página de prototipos
│ └─ EssayPage.jsx # Página de ensayos con TOC
├─ /essays # Contenido MDX
│ └─ crafting-cruma.mdx # Ensayo sobre Cruma
├─ /styles # Estilos CSS personalizados
│ └─ essay.css # Estilos específicos para ensayos
├─ /content # Datos de proyectos
│ ├─ homeItems.js # Configuración de proyectos
│ └─ ordering.js # Orden de navegación
└─ /images # Imágenes estáticas
-
Cloná el repositorio:
git clone https://github.com/franlopezmora/portafolio-FLM.git cd portafolio-FLM -
Instalá dependencias:
npm install
-
Iniciá el servidor de desarrollo:
npm run dev
- Layout Masonry – Grid responsivo con tarjetas de proyectos
- Modo oscuro – Toggle automático con persistencia en localStorage
- Diseño centrado – Contenido centrado a 1100px máximo
- Sin scroll horizontal – Optimizado para evitar overflow
- Soporte multiidioma – Español e inglés con cambio dinámico
- TOC fijo – Tabla de contenidos que permanece en posición al hacer scroll
- Imágenes adaptativas – Fijas a 900px, se adaptan fluidamente por debajo
- Texto centrado – Contenido limitado a 720px para mejor legibilidad
- Responsive inteligente – TOC se oculta <1200px, contenido se centra
- WebPreview – Componente para mostrar demos en vivo de proyectos web
- Ensayos bilingües – Versiones en español e inglés
- 7 prototipos – Demos en vivo de componentes UI
- Layout consistente – Header con título, fecha y toggle de modo oscuro
- Navegación prev/next – Entre prototipos y ensayos
- Componentes embebidos – Sidebar, tooltips, inputs animados
- Descripciones traducidas – Contenido en español e inglés
- Paleta neutral – Grises y blancos con soporte para modo oscuro
- Tipografía clara – Jerarquía visual bien definida
- Animaciones sutiles – Transiciones suaves sin ser intrusivas
- Accesibilidad – Navegación por teclado y ARIA labels
- Internacionalización – Sistema completo de traducciones ES/EN
Generación automática de placeholders (~30px) para imágenes y primer frame de videos.
- Manifest:
/public/media-manifest.json - Thumbnails:
/public/lqip/*.png
Scripts:
npm run lqip # genera manifest + lqip
npm run build # corre lqip y luego vite buildRequisitos:
- Node 18+
- Dev deps:
sharp,undici - ffmpeg (opcional): solo si un video no trae
poster
Notas:
- Si cambiás
homeItems, corrénpm run lqipantes del deploy. - Para inline (sin requests a
/lqip/*.png), activáINLINE_LQIPenscripts/build-lqip-from-homeitems.mjs.
Componente para mostrar demos en vivo de proyectos web dentro de ensayos MDX.
import WebPreview from "../components/WebPreview.jsx";
<WebPreview
url="https://ejemplo.com"
image="/images/previews/ejemplo.png"
title="Mi Proyecto — Live Demo"
/>url(string): URL del sitio webimage(string): Ruta de la imagen previewtitle(string, opcional): Título debajo de la card
- Aspect ratio 16:9 fijo
- Hover con escala y overlay "Visitar"
- Enlace externo con
target="_blank" - Soporte para modo oscuro
- Responsive y accesible
Componente para mostrar múltiples imágenes en diferentes layouts dentro de ensayos MDX.
import EssayCollage from "../components/EssayCollage.jsx";
<EssayCollage
layout="grid"
images={[
{ src: "imagen1.png", alt: "Descripción 1" },
{ src: "imagen2.png", alt: "Descripción 2" },
{ src: "imagen3.png", alt: "Descripción 3" },
{ src: "imagen4.png", alt: "Descripción 4" }
]}
/>images(array): Array de objetos consrcyalt, o strings simpleslayout(string): "grid", "horizontal", "vertical", "masonry"gap(string, opcional): Clase de Tailwind para espaciado (default: "gap-2")className(string, opcional): Clases CSS adicionales
- grid: Cuadrícula 2x2 (ideal para 4 imágenes)
- horizontal: Imágenes en fila horizontal
- vertical: Imágenes en columna vertical
- masonry: Layout tipo Pinterest con columnas
- Border radius 12px automático
- Soporte para captions opcionales
- Responsive y adaptable
- Integración perfecta con el diseño de ensayos
Componente para mostrar bloques de código con sintaxis highlighting y botón de copiar.
import CodeBlock from "../components/CodeBlock.jsx";
<CodeBlock
language="tsx"
filename="Grid.tsx"
code={`interface CellProps {
row: number;
column: number;
children: React.ReactNode;
}
function Cell({ row, column, children }: CellProps) {
return (
<div className="grid-cell" style={{ gridRow: row, gridColumn: column }}>
{children}
</div>
);
}`}
/>code(string): El código a mostrarlanguage(string): Lenguaje para syntax highlighting (default: "tsx")filename(string, opcional): Nombre del archivo a mostrar en el headerclassName(string, opcional): Clases CSS adicionales
- Botón "Copiar" con feedback visual
- Soporte para syntax highlighting (Prism/Shiki)
- Header con nombre de archivo y lenguaje
- Responsive y adaptable al modo oscuro
Editor de código interactivo con preview en vivo usando iframe.
import EditableCode from "../components/EditableCode.jsx";
<EditableCode
filename="demo.html"
height={360}
initialHtml={`<div id="app"></div>`}
initialCss={`body{display:grid;place-items:center;height:100vh}`}
initialJs={`document.getElementById('app').textContent = 'Hola 👋';`}
/>initialHtml(string): HTML inicialinitialCss(string): CSS inicialinitialJs(string): JavaScript inicialheight(number): Altura del preview (default: 340)filename(string): Nombre del archivo (default: "demo.html")autoRunDelay(number): Delay para auto-ejecutar cambios (default: 400ms)className(string, opcional): Clases CSS adicionales
- Editor con tabs HTML/CSS/JS
- Preview en vivo con iframe
- Auto-ejecución con debounce
- Botones "Run" y "Reset"
- Indicador de cambios pendientes
- Manejo de errores JavaScript
- Responsive (editor + preview en desktop, stack en mobile)
Soporte para .tsx. ProyectoCard.tsx usa ProyectoCardProps para tipado estricto.
Recomendado commitear public/media-manifest.json y public/lqip/* generados localmente para evitar ffmpeg en build de Vercel.
- Desktop (>1200px): Layout completo con TOC fijo y contenido centrado
- Tablet (960-1199px): TOC oculto, contenido centrado, imágenes adaptativas
- Mobile (<960px): Layout de una columna, masonry responsivo
Este diseño está inspirado en la estética limpia y funcional de rauno.me, adaptado para mostrar mis propios proyectos y experiencia como desarrollador fullstack.
- Email: franciscolopezmora3@gmail.com
- GitHub: franlopezmora
- LinkedIn: Francisco López Mora
Desarrollado con ❤️ en React y Vite