diff --git a/package.json b/package.json
index d3a292e..25359d9 100644
--- a/package.json
+++ b/package.json
@@ -10,6 +10,7 @@
"babel-polyfill": "^6.26.0",
"babel-preset-env": "^1.7.0",
"babel-preset-gatsby": "^0.5.14",
+ "classnames": "^2.2.6",
"gatsby": "^2.24.85",
"gatsby-legacy-polyfills": "0.0.5",
"gatsby-plugin-manifest": "2.4.31",
diff --git a/src/components/UI/blog-entries/blog-entries.js b/src/components/UI/blog-entries/blog-entries.js
new file mode 100644
index 0000000..e85714c
--- /dev/null
+++ b/src/components/UI/blog-entries/blog-entries.js
@@ -0,0 +1,69 @@
+import React from "react";
+import CardFactory from "../card/card-factory";
+import { getStyles } from "./utils";
+import { BlogGrid, BlogCard } from "./styles";
+
+// TODO: Fake city & event cards
+const fakeCardsData = [
+ // {
+ // id: 5,
+ // title: "Trabajo Remoto",
+ // subtitle: "Enero 16 - 17:00",
+ // url_img:
+ // "https://javascriptecuador.netlify.app/static/quito-605ac9d2e0009a60014111b3bedf73c9.jpg",
+ // description_title: "Disertantes",
+ // description: "Crysfel Villa, Freddy Santacruz",
+ // url_entry: "!#",
+ // type: "event",
+ // },
+ // {
+ // id: 6,
+ // title: "Guayaquil.js",
+ // subtitle: null,
+ // url_img:
+ // "https://javascriptecuador.netlify.app/static/quito-605ac9d2e0009a60014111b3bedf73c9.jpg",
+ // description_title: "Descripción",
+ // description:
+ // "Lorem ipsum dolor sit amet consectetur adipisicing elit. Ab, voluptas. Aperiam cumque minus eius itaque odio ullam quam repudiandae delectus. Totam, eveniet deserunt. Nobis, mollitia natus! Architecto alias asperiores rerum.",
+ // url_entry: "!#",
+ // author: "Crysfel Villa, Freddy Santacruz",
+ // type: "city",
+ // },
+];
+
+const BlogEntries = ({ data }) => {
+ const styles = getStyles(data.length);
+ const cards = data.map((card, index) => {
+ console.log(card);
+ const {
+ gridRow,
+ widthImg,
+ gridColumn,
+ flexDirection,
+ paddingLeftContent,
+ paddingTopContent,
+ paddingBottomTitle,
+ paddingBlockFooter,
+ } = styles[index];
+
+ return (
+
+
+
+ );
+ });
+
+ return {cards};
+};
+
+export default BlogEntries;
diff --git a/src/components/UI/blog-entries/styles.js b/src/components/UI/blog-entries/styles.js
new file mode 100644
index 0000000..e068e34
--- /dev/null
+++ b/src/components/UI/blog-entries/styles.js
@@ -0,0 +1,105 @@
+import styled from "styled-components";
+import {
+ Card,
+ CardContent,
+ CardImg,
+ CardTitle,
+ CardFooter,
+} from "../card/styles";
+import { card } from "../../../constants/card.config";
+
+const BlogGrid = styled.div`
+ display: grid;
+ grid-column-gap: 3%;
+ grid-row-gap: 15px;
+ grid-template-rows: auto;
+
+ /* Small devices (landscape phones, 320px and up) */
+ @media (min-width: 320px) {
+ & {
+ grid-template-columns: 1fr;
+ }
+ }
+
+ /* Extra arge devices (extra large desktops, 1201px and up) */
+ @media (min-width: 1201px) {
+ & {
+ grid-template-columns: auto 45% auto;
+ }
+ }
+`;
+const BlogCard = styled.div`
+ grid-row: ${(props) => props.gridRow};
+ grid-column: ${(props) => props.gridColumn};
+
+ & > ${Card} {
+ flex-direction: ${(props) => props.flexDirection};
+ }
+
+ & ${CardContent} {
+ padding-left: ${(props) => props.paddingLeftContent}em;
+ }
+
+ /* Small devices (landscape phones, 320px and up) */
+ @media (min-width: 320px) {
+ & {
+ grid-area: auto;
+ }
+
+ & > ${Card} {
+ flex-direction: column;
+ }
+
+ & ${CardContent} {
+ padding-left: 0;
+ }
+ }
+
+ /* Extra large devices (extra large desktops, 1201px and up) */
+ @media (min-width: 1201px) {
+ & {
+ grid-row: ${(props) => props.gridRow};
+ grid-column: ${(props) => props.gridColumn};
+ }
+
+ & > ${Card} {
+ flex-direction: ${(props) => props.flexDirection} !important;
+ }
+
+ & ${CardContent} {
+ padding-left: ${(props) => props.paddingLeftContent}em !important;
+ padding-top: ${(props) => props.paddingTopContent}em !important;
+ }
+
+ & ${CardImg} {
+ width: ${(props) => props.widthImg} !important;
+ }
+ }
+
+ /* large devices (large desktops, 768px and up) */
+ @media (min-width: 768px) {
+ & > ${Card} {
+ flex-direction: row;
+ }
+
+ & ${CardContent} {
+ padding-left: 1em;
+ padding-top: 0;
+ }
+
+ & ${CardImg} {
+ width: ${card.blog.viewport_img_height}em;
+ background-position: left center;
+ }
+
+ & ${CardTitle} {
+ padding-bottom: ${(props) => props.paddingBottomTitle}em;
+ }
+
+ & ${CardFooter} {
+ padding-block: ${(props) => props.paddingBlockFooter}em;
+ }
+ }
+`;
+
+export { BlogGrid, BlogCard };
diff --git a/src/components/UI/blog-entries/utils.js b/src/components/UI/blog-entries/utils.js
new file mode 100644
index 0000000..e4f3d8e
--- /dev/null
+++ b/src/components/UI/blog-entries/utils.js
@@ -0,0 +1,87 @@
+import { card } from "../../../constants/card.config";
+
+const loop = (states, pos, cb) => states[pos].map(cb);
+
+const getDistribution = (cardsLength) => {
+ const states = [
+ [0, 0, 0],
+ [0, 1, 0],
+ [1, 1, 0],
+ [1, 1, 1],
+ ];
+ const jumpRelation = [1, 2, 1];
+ const statePosition = cardsLength % states.length;
+ const stateMultiplier = Math.trunc(cardsLength / states.length);
+
+ return {
+ inLength: () =>
+ loop(states, statePosition, (column, pos) => {
+ return column + jumpRelation[pos] * stateMultiplier;
+ }),
+ inRange: () => {
+ let endRange = 0;
+ let maxColumnSize = 0;
+ return loop(states, statePosition, (column, pos) => {
+ maxColumnSize = column + jumpRelation[pos] * stateMultiplier;
+ endRange += maxColumnSize;
+ return [endRange - maxColumnSize, endRange];
+ });
+ },
+ };
+};
+
+class BlogCardStyle {
+ constructor({
+ gridRow,
+ widthImg,
+ gridColumn,
+ flexDirection,
+ paddingLeftContent,
+ paddingTopContent,
+ paddingBottomTitle,
+ paddingBlockFooter,
+ }) {
+ this.gridRow = gridRow;
+ this.widthImg = widthImg;
+ this.gridColumn = gridColumn;
+ this.flexDirection = flexDirection;
+ this.paddingLeftContent = paddingLeftContent;
+ this.paddingTopContent = paddingTopContent;
+ this.paddingBottomTitle = paddingBottomTitle;
+ this.paddingBlockFooter = paddingBlockFooter;
+ }
+}
+
+const getStyles = (dataLength) => {
+ let styles = [];
+ const distribution = getDistribution(dataLength).inLength();
+
+ distribution.forEach((maxColumnSize, pos) => {
+ const columnStart = pos + 1;
+ const columnEnd = pos + 2;
+ const isMiddle = pos !== 0 && pos !== distribution.length - 1;
+
+ for (let index = 0; index < maxColumnSize; index++) {
+ const rowStart = isMiddle ? index + 1 : 2 * index + 1;
+ const rowEnd = isMiddle ? index + 2 : rowStart + 2;
+
+ styles = [
+ ...styles,
+ new BlogCardStyle({
+ gridRow: `${rowStart} / ${rowEnd}`,
+ widthImg: isMiddle ? `${card.blog.viewport_img_height}em` : "initial",
+ gridColumn: `${columnStart} / ${columnEnd}`,
+ flexDirection: isMiddle ? "row" : "column",
+ paddingLeftContent: Number(isMiddle),
+ paddingTopContent: isMiddle ? "initial" : 1,
+ paddingBottomTitle: isMiddle ? 0.5 : 1,
+ paddingBlockFooter: isMiddle ? 0.5 : 1,
+ }),
+ ];
+ }
+ });
+
+ return styles;
+};
+
+export { getStyles };
diff --git a/src/components/UI/card/card-design.js b/src/components/UI/card/card-design.js
new file mode 100644
index 0000000..e7a9f95
--- /dev/null
+++ b/src/components/UI/card/card-design.js
@@ -0,0 +1,72 @@
+import React from "react";
+import PropTypes from "prop-types";
+import {
+ Card,
+ CardImg,
+ CardBody,
+ CardContent,
+ CardTitle,
+ CardSubtitle,
+ DescriptionTitle,
+ CardDescription,
+ ReadMoreLink,
+ CardFooter,
+ FooterLine,
+} from "./styles";
+
+export const CardDesign = ({ data, optionalData, styles }) => {
+ const {
+ id,
+ img,
+ title,
+ subtitle,
+ description,
+ description_title,
+ url_entry,
+ } = data;
+ const optDataKeys = Object.keys(optionalData);
+ const hasOptData = optDataKeys.length > 0;
+ const printSubtitle = subtitle && (
+
+ {subtitle}
+
+ );
+ const printFooterLines = optDataKeys.map((name, index) => (
+
+ {optionalData[name]}
+
+ ));
+
+ return (
+
+
+
+
+
+ {title}
+
+ {printSubtitle}
+
+ {description_title}:{" "}
+ {description}{" "}
+
+
+ Leer más
+
+ {hasOptData && {printFooterLines}}
+
+
+
+ );
+};
+
+CardDesign.propTypes = {
+ data: PropTypes.object.isRequired,
+ optionalData: PropTypes.object,
+ styles: PropTypes.object.isRequired,
+};
+
+export default CardDesign;
diff --git a/src/components/UI/card/card-factory.js b/src/components/UI/card/card-factory.js
new file mode 100644
index 0000000..be02a07
--- /dev/null
+++ b/src/components/UI/card/card-factory.js
@@ -0,0 +1,58 @@
+import React from "react";
+import PropTypes from "prop-types";
+import { CardDesign } from "./card-design";
+import { card } from "../../../constants/card.config";
+
+// For more info, visit the following url:
+// https://dev.to/shadid12/react-js-with-factory-pattern-building-complex-ui-with-ease-1ojf
+const CardFactory = ({ entry }) => {
+ const {
+ id,
+ img,
+ type,
+ title,
+ subtitle,
+ description,
+ description_title,
+ url_entry,
+ direction,
+ ...others
+ } = entry;
+ const dataEntry = {
+ id,
+ img,
+ title,
+ subtitle,
+ description,
+ description_title,
+ url_entry,
+ direction,
+ };
+
+ switch (type) {
+ case "blog":
+ return (
+
+ );
+ case "city":
+ return (
+
+ );
+ case "event":
+ return (
+
+ );
+ default:
+ return
Cargando...
;
+ }
+};
+
+CardFactory.propTypes = {
+ entry: PropTypes.object.isRequired,
+};
+
+export default CardFactory;
diff --git a/src/components/UI/card/card.js b/src/components/UI/card/card.js
index 9e88e47..96e50d3 100644
--- a/src/components/UI/card/card.js
+++ b/src/components/UI/card/card.js
@@ -6,12 +6,12 @@ import { Link } from "gatsby";
const Card = ({
imgURL,
topic,
- dateTime,
- descriptionTitle,
+ topicFontSize,
description,
+ descriptionTitle,
link,
readMoreColor,
- topicFontSize,
+ dateTime,
viewportHeight,
textSpacing,
lineHeight,
diff --git a/src/components/UI/card/styles.js b/src/components/UI/card/styles.js
new file mode 100644
index 0000000..4285978
--- /dev/null
+++ b/src/components/UI/card/styles.js
@@ -0,0 +1,95 @@
+import { Link } from "gatsby";
+import styled from "styled-components";
+
+const MAX_LINES = 2;
+const BORDER_RADIUS = 10;
+const NEUTRAL_COLOR = "#666363";
+const TRANSPARENT_COLOR = "transparent";
+const PADDING = 0;
+// values in em units
+const FONT_SIZE_BASE = 1; /* 16px */
+const FONT_SIZE_L = FONT_SIZE_BASE + 0.2; /* 19.2px */
+const FONT_SIZE_M = FONT_SIZE_BASE - 0.1; /* 14.4px */
+const FONT_SIZE_S = FONT_SIZE_BASE - 0.2; /* 11.8px */
+const SPACING = 1; /* 16px */
+const LINE_HEIGHT_DESC = 1.4; /* 22.4px */
+const LINE_HEIGHT_FOOT = 1; /* 4.8px */
+
+const Card = styled.div`
+ width: 100%;
+ /* max-width: ; */
+ display: flex;
+ padding: ${(props) => props.allPadding || PADDING}em;
+ border-radius: ${BORDER_RADIUS}px;
+ background-color: ${(props) => props.bgColor || TRANSPARENT_COLOR};
+`;
+const CardImg = styled.div`
+ width: 100%;
+ border-radius: ${BORDER_RADIUS}px;
+ height: ${(props) => props.maxHeight}em;
+ background-image: url(${(props) => props.bgImg});
+ background-size: cover;
+ background-position: center center;
+ flex-grow: 1;
+`;
+const CardBody = styled.div`
+ flex-grow: 1;
+`;
+const CardContent = styled.div`
+ padding-top: 1em;
+ line-height: ${LINE_HEIGHT_DESC}rem;
+`;
+const CardTitle = styled.h5`
+ padding-bottom: ${(props) => props.paddingBottom}em;
+ font-size: ${(props) => props.fontSize || FONT_SIZE_L}em;
+ font-weight: bold;
+`;
+const CardSubtitle = styled(CardTitle)`
+ font-size: ${(props) => props.fontSize || FONT_SIZE_BASE}em;
+ color: ${NEUTRAL_COLOR};
+`;
+const DescriptionTitle = styled.span`
+ font-weight: bold;
+`;
+const CardDescription = styled.p`
+ font-size: ${FONT_SIZE_M}em;
+ display: -webkit-box;
+ -webkit-line-clamp: ${MAX_LINES};
+ -webkit-box-orient: vertical;
+ overflow: hidden;
+`;
+const ReadMoreLink = styled(Link)`
+ color: ${(props) => props.color};
+ font-size: ${FONT_SIZE_M}em;
+ font-weight: bold;
+`;
+const CardFooter = styled.div`
+ padding: 1em 0;
+ display: flex;
+ flex-direction: column;
+`;
+const FooterLine = styled.span`
+ font-size: ${(props) =>
+ props.pos === 0
+ ? FONT_SIZE_BASE
+ : props.pos === 1
+ ? FONT_SIZE_M
+ : FONT_SIZE_S}em;
+ line-height: ${(props) =>
+ [0, 2].includes(props.pos) ? `${LINE_HEIGHT_FOOT}em` : ""};
+ color: ${(props) => ([1, 2].includes(props.pos) ? NEUTRAL_COLOR : "")};
+`;
+
+export {
+ Card,
+ CardImg,
+ CardBody,
+ CardContent,
+ CardTitle,
+ CardSubtitle,
+ DescriptionTitle,
+ CardDescription,
+ ReadMoreLink,
+ CardFooter,
+ FooterLine,
+};
diff --git a/src/components/blog-section/blog-section.js b/src/components/blog-section/blog-section.js
index 7f0a94f..518c3e1 100644
--- a/src/components/blog-section/blog-section.js
+++ b/src/components/blog-section/blog-section.js
@@ -1,8 +1,64 @@
-import React from 'react';
-import styles from './blog-section.module.css';
+import React from "react";
+import { StaticQuery, graphql } from "gatsby";
+import BlogEntries from "../UI/blog-entries/blog-entries";
+import { BlogWrapper, BlogTitle, BlogMore, BlogLink } from "./styles";
-const BlogSection = () => (
-
+const BlogSection = (entries) => {
+ return (
+
+ Blog
+
+
+ Leer más
+
+
+ );
+};
+
+const RenderBlogSection = () => (
+ {
+ const lastFiveEntries = data.articulos.nodes.map((entry) => {
+ return {
+ ...entry.frontmatter,
+ id: entry.id,
+ url_entry: `/blog/${entry.path}`,
+ img: entry.frontmatter.img.publicURL,
+ author: entry.frontmatter.author.name,
+ timeago: `${entry.timeToRead} min. Lectura`,
+ description_title: "Descripción",
+ type: "blog",
+ };
+ });
+
+ return BlogSection(lastFiveEntries);
+ }}
+ >
);
-export default BlogSection;
+export default RenderBlogSection;
diff --git a/src/components/blog-section/blog-section.module.css b/src/components/blog-section/blog-section.module.css
deleted file mode 100644
index 17444e4..0000000
--- a/src/components/blog-section/blog-section.module.css
+++ /dev/null
@@ -1,3 +0,0 @@
-.blogSection {
- height: 923px;
-}
\ No newline at end of file
diff --git a/src/components/blog-section/styles.js b/src/components/blog-section/styles.js
new file mode 100644
index 0000000..34bfec0
--- /dev/null
+++ b/src/components/blog-section/styles.js
@@ -0,0 +1,25 @@
+import { Link } from "gatsby";
+import styled from "styled-components";
+
+const BlogWrapper = styled.section`
+ background: #fff;
+ /* height: 840px; */
+ padding-top: 10em;
+ position: relative;
+`;
+const BlogTitle = styled.h2`
+ margin-bottom: 1em;
+`;
+const BlogMore = styled.div`
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ padding: 2.5em;
+`;
+const BlogLink = styled(Link)`
+ font-weight: bold;
+ font-size: 1.5em;
+ color: #056294;
+`;
+
+export { BlogWrapper, BlogTitle, BlogMore, BlogLink };
diff --git a/src/components/layout/layout.js b/src/components/layout/layout.js
index 9f0aed0..5a7826b 100644
--- a/src/components/layout/layout.js
+++ b/src/components/layout/layout.js
@@ -4,7 +4,7 @@ import Footer from "../footer/footer";
import Header from "../header/header";
import styles from "./layout.module.css";
import pathImg from "../../images/background/path.svg";
-import BlogSection from "../blog-section/blog-section";
+import RenderBlogSection from "../blog-section/blog-section";
import Subscribe from "../subscribe/subscribe";
const Layout = ({ isHome, children }) => {
@@ -13,7 +13,7 @@ const Layout = ({ isHome, children }) => {
if (isHome) {
background = pathImg;
- blogSection = ;
+ blogSection = ;
}
return (
diff --git a/src/constants/card.config.js b/src/constants/card.config.js
new file mode 100644
index 0000000..8875568
--- /dev/null
+++ b/src/constants/card.config.js
@@ -0,0 +1,33 @@
+export const card = {
+ blog: {
+ link_color: "blue",
+ viewport_img_height: 10,
+ spacing: 1,
+ },
+ city: {
+ title_size: 2, // em units
+ link_color: "green",
+ bg_color: "#e0e0e0",
+ viewport_img_height: 13,
+ spacing: 1,
+ padding: 1.3,
+ },
+ event: {
+ title_size: 1, // em units
+ subtitle_size: 1, // em units
+ link_color: "#046294",
+ bg_color: "#e0e0e0",
+ viewport_img_height: 15,
+ spacing: 0,
+ padding: 1.3,
+ },
+ base: {
+ title_size: 1.2, // em units
+ subtitle_size: 1, // em units
+ link_color: "blue",
+ bg_color: "blue",
+ viewport_img_height: 1.1,
+ spacing: 0.5, // em units
+ padding: 1.3,
+ },
+};
diff --git a/src/pages/blog.js b/src/pages/blog.js
index c921950..b01d56d 100644
--- a/src/pages/blog.js
+++ b/src/pages/blog.js
@@ -15,7 +15,14 @@ function BlogPage(articulos) {
@@ -29,14 +36,20 @@ function renderBlogPage() {
{
- const articulosFormateados = data.articulos.edges.map((articulo) => {
+ const articulosFormateados = data.articulos.nodes.map((articulo) => {
return {
- ...articulo.node.frontmatter,
- slug: articulo.node.slug,
- id: articulo.node.id,
+ ...articulo.frontmatter,
+ id: articulo.id,
+ url_entry: `/blog/${articulo.path}`,
+ img: articulo.frontmatter.img.publicURL,
+ author: articulo.frontmatter.author.name,
+ timeago: `${articulo.timeToRead} min. Lectura`,
+ description_title: "Descripción",
+ type: "blog",
};
});
+
return BlogPage(articulosFormateados);
}}
/>
diff --git a/src/pages/blog/gatsby-deploy/header.jpg b/src/pages/blog/gatsby-deploy/header.jpg
new file mode 100644
index 0000000..ec02eda
Binary files /dev/null and b/src/pages/blog/gatsby-deploy/header.jpg differ
diff --git a/src/pages/blog/gatsby-deploy.mdx b/src/pages/blog/gatsby-deploy/index.mdx
similarity index 89%
rename from src/pages/blog/gatsby-deploy.mdx
rename to src/pages/blog/gatsby-deploy/index.mdx
index 1de08c3..459e21e 100644
--- a/src/pages/blog/gatsby-deploy.mdx
+++ b/src/pages/blog/gatsby-deploy/index.mdx
@@ -1,9 +1,10 @@
---
title: Deploy de un sitio de Gatsby en Netlify
-date: "2020-10-05"
-updated: "2020-10-05"
+date: "2021-02-11"
+updated: "2020-02-11"
+img: ./header.jpg
description: Como realizar el deploy de un sitio construido con Gatsby a Netlify
-author: "https://github.com/edzzn"
+author: "https://github.com/israteneda"
---
Esta es la guía base para realizar el deploy de una página construida con el framework Gatsby,
@@ -19,6 +20,7 @@ Una vez tenemos el sitio alojado en un repositorio de GitHub tenemos que conecta
2. Conectar el repositorio
Hacer clic en el botón que lleva a la pantalla donde Netlify se conecta al repositorio de GitHub.
+ftefsdf
![](https://cdn.netlify.com/6cc161f3ced8f060296bc8aeacd7fb39e5159274/743e1/img/blog/create_link_repo.png)
@@ -60,4 +62,9 @@ los cambios también están disponibles en Internet.
Espera, ¿pensaste que habría más? ¡No! Netlify lo ha hecho, incluido darle un nombre temporal al sitio.
El sitio estará activo para que lo vea el público y si se desea se puede agregar un dominio personalizado.
-Tomado de A Step-by-Step Guide: Gatsby on Netlify
\ No newline at end of file
+
+ Tomado de{" "}
+
+ A Step-by-Step Guide: Gatsby on Netlify
+
+