Lecciones del curso

Aprende Remix construyendo un Blog con MongoDB y Netlify

Clonando el proyecto
2m
Anatomía del proyecto
4m
Agregando TailwindCSS
3m
Creando y conectando con la base de datos
8m
Ruta para el login
Maquetando el dashboard
Editando posts | Primera parte
Editando posts | Segunda parte
Preparando el UI público
Redireccionando en la Página de inicio
Vista de lista
CSS para el Markdown
Blog listo para producción con Netlify
Creando Feedlinks (SSR)
Creando un sitemap.xml
Felicitación y despedida

Vista de lista

Vamos a la ruta /blog., y escribamos el código necesario para mostrar un mensaje y todos nuestros posts.

Esta será la ruta para mostrar nuestros posts en una lista atractiva. También contendrá un saludo amistoso, junto con nuestros datos si es un blog personal o los de marca. ®️

Para ello necesitaremos algunos datos de cada post, pero no todos, solo los necesarios.

Por eso, vamos a escribir el loader primero.

Escribiendo el loader

¿Qué datos necesitamos? Depende del diseño del componente <BlogCard>, pero por ahora pediremos tres: title, createdAt y author.

export const loader: LoaderFunction = async () => { const posts = await db.posts.findMany({ where: { published: true }, select: { title: true, createdAt: true, author: true, }, }); return { posts }; };

Toma nota de que he aplicado un filtro, pues solo queremos los posts que posean la llave published como true.

👀 También observa que al pedir author:true estamos haciendo uso de la relación uno a muchos definida en el schema de Prisma. — Puedes revisar la lección Conectando con la base de datos ✅ para recordar esto.

Escribiendo el cliente

Ahora coloquemos el JSX de nuestro cliente, que ofrecerá un saludo y la lista de los posts. Pero comencemos con el saludo:

// app/routes/blog.tsx export default function Blog() { return ( <> <h2>¡Hola! 👋🏼 Bienvenid@ a mi blog.</h2> <p> Soy @blissmo 🤓 y me gusta compartir lo que aprendo sobre desarrollo web. </p> </> ); }

👋🏼 ¡Hola! Disfruto de programar, igual que tu. 🤓

Agregando una imagen y un mejor “copy

Me gustan las versiones minimalistas que a veces me resultan en estos cursos, disfruto de imaginar la mínima interfaz posible. No, no importa si no tiene todas las recomendaciones de diseño, buenas prácticas y espaciados, me preocupo de la accesibilidad claro, pero la estética queda subordinada a la usabilidad.

Es bonito construir un app que funcione, sin la presión de hacerlo todo perfecto o estético.

preview

Por eso no he agregado más, que un par de párrafos y una imagen:

<> <main className="max-w-3xl mx-auto py-20 px-4 flex justify-between gap-4 items-center"> <div> <h2 className="font-medium text-4xl text-white"> ¡Hola! 👋🏼 Bienvenid@ a mi jardín digital. 🪴 </h2> <p className="text-2xl font-thin my-4 text-gray-200"> Soy @blissmo 🤓 y me gusta compartir lo que aprendo sobre desarrollo web independiente. </p> <p className="text-2xl my-4 text-gray-200"> Ultimamente intento escribir y narrar bien. ✍🏼 </p> </div> <img className="rounded-3xl max-w-xs hover:rotate-3 hover:scale-105 transition-all" src="https://i.imgur.com/OtuQ5J8.png" alt="Chilango at Prague" /> </main> <section> {posts.map((post) => ( <BlogCard {...post} key={post.id} /> ))} </section> {posts.length < 1 && ( <p className="bg-gray-600 text-gray-200 text-center py-12 max-w-3xl mx-auto block rounded-2xl text-xl font-thin hover:scale-95 transition-all"> {" "} No he escrito nada aún 😥{" "} </p> )} </>

¡Tú puedes crear tu propia versión, por su puesto! 👩🏻‍🎨

Pero por ahora con este <section> vamos a contener todos nuestros posts, utilizando el componente <BlogCard> que escribiremos en un momento.

Ahora, vamos a trabajar con <BlogCard> para que muestre el título de cada posts con un buen tamaño, junto a una pequeña imagen como thumbnail.

Finalizando el maquetado

Hay un montón de diseños hermosos allá afuera, pero este curso está pensado para construir un app funcional, real, lista para producción. Así que tengo que repetir que, puedes mejorar el diseño de esta tarjeta. Pero yo me conformo, este componente es suficientemente bello y muy útil, nos sirve para mostrar nuestros posts, así que nos gusta. 🌀

preview

Vamos a crear esta tarjeta para usarla en nuestra ruta /blog.tsx y poder mostrar todos nuestros posts.

Escribiendo <BlogCard>

Este componente es el responsable de mostrar nuestros posts de manera vistosa, además de colocar un enlace para llevar a nuestro usuario al detalle, mismo que escribiremos en la siguiente lección.

// app/components/BlogCard.tsx import { Link } from "@remix-run/react"; import relativeTime from "dayjs/plugin/relativeTime"; import dayjs from "dayjs"; // Mi biblioteca favorita para fechas import "dayjs/locale/es-mx"; dayjs.extend(relativeTime); dayjs.locale("es-mx"); export const BlogCard = ({ title, slug, cover, createdAt, }: { createdAt: string | Date; cover?: string; slug: string; title: string | null; }) => { return ( <Link to={`${slug}`} className="bg-gradient-to-r from-slate-600 to-slate-800 text-white p-4 rounded-md hover:ring-indigo-500 hover:ring transition-all w-full flex items-center gap-4" > <img src={cover} alt="cover" className="rounded-sm object-cover max-w-xs" /> <div> <h3 className="text-3xl"> {title}</h3> <span className="font-thin text-sm text-gray-300"> {dayjs(createdAt).from(new Date())} // @Reto: este dato debería venir del modelo </span> </div> </Link> ); };

toma nota de que usamos dayjs para no perder tiempo con los formatos de fecha.

dayjs necesita más configuración que momentjs (1 línea más 😅) pero pesa menos de 2kb y tiene herramientas bien buenas, como la que estoy usando. 😎

Agrega un par de posts desde tu dashboard, y hazlos públicos

Agrega dos post a tu blog para poder trabajar en la ruta dinámica que sigue.

Necesitamos una vista de detalle, que será el espacio de lectura de nuestro usuario, y necesitamos que sea lo más agradable posible.

Vayamos pues a construir la ruta dinámica para el detalle. 🚀

spaceman

¿List@ para ver todo el curso? Prepárate porque apenas estamos comenzando 🚀

¡Desbloquea el curso completo y conviértete en un PRO del desarrollo web! 🫶🏻 .