Let’s understand Gatsby JS with a blog site

components folder
pages folder
templates folder
  1. Setup and Installation
  • make sure you have node js installed (for this proj we are using version — 14.15.0 ) Node.js website
  • install gatsby CLI globally (npm install -g gatsby-cli)
  • Now we will generate a new application using with command
  • gatsby new name_of_the_app starter_url
  • gatsby new blogsite (we are omiting starter template url for this project)
  • Also we will try to deploy it to netlify too! (optional point)
  • cd blogsite and open it using visual studio code or any other code editor
  • open package.json file and we can see these packages installed VIZ,

In the index.js file as you can see it’s a functional react component and we have an arrow function here

  • Add what is JSX here and explain it breifly
  • In index.js file only we have SEO component we are importing “react-helmet”
  • from which we will destructure “Helmet”
  • so, Helmet deals with the head section/tag and is used manage SEO
  • As you can see we have title and also we can inlcude meta info such as description and keywords
  • also we have GraphQL query below ( Optional point )
  • so we can use global styling or SASS or styled components
  • In this demo we are going to use css files and inline styles in some cases
  • that we are passing it as a props and can be changed from “gatsby-config.js
  • by running the command: gatsby develop
  • it will open site on “localhost:8000”
  • and this dev-server has hot reload (so as soon as you save your page browser gets updated with latest changes)
  • Link tag is used instead of anchor tag and it is obtained from “gatsby-link” package and has a “to” attribute
  • we can change the “siteTitle” from gatsby-config.js . If we change config file we need to restart the dev server. (after reload show them head tag in the browser to view SEO tags)
  • add some dummy text and save and show them hot reload and tell them if they want they can use bootstrap, materliaze or CSS grid
import * as React from "react"import Layout from "../components/layout"
import Seo from "../components/seo"
import "./common.css";
const IndexPage = () => (
<Layout>
<Seo title="Home" description="Blog site home page" />
<header id="page-title" className="jumbotron background">
<div className="container">
<div className="horizontal-center vertical-center">
<h1 className="article-title">Welcome to your own Gatsby site.</h1>
<h2 className="article-subtitle"><span>&#8220;</span>Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better.<span>&#8221;</span></h2>
</div>
</div>
</header>
</Layout>
)
export default IndexPage
  • create a page inside of “Pages” folder called “about.js”
  • Now to create a component we use VS-Code plugin called “ES7/React/Redux/GraphQL”
  • then type ‘rfce’ and hit tab to create functional component
  • rcc — will give you a class based component
  • export that component and show the demo by going to about page.
  • Generally in React we use react-router or Route but in Gatsby we don’t need to use that it handle that on it’s own (behind the scene)
  • all you got to do is to create the page in the pages-folder and gatsby will handle it
import React from 'react'import Layout from "../components/layout"
import Seo from "../components/seo"
import "./common.css";
const about = () => (
<Layout>
<Seo title="About" description="Blog site about page" />
<header id="page-title" className="jumbotron background">
<div className="container">
<div className="horizontal-center vertical-center">
<h1 className="article-title">About Us</h1>
<h2 className="article-subtitle"><span>&#8220;</span>When something is important enough, you do it even if the odds are not in your favor.<span>&#8221;</span></h2>
</div>
</div>
</header>
</Layout>
)
export default about
  • create a “services.js” page inside pages folder from about page and go to that route and demo that page
import React from 'react'import Layout from "../components/layout"
import Seo from "../components/seo"
import "./common.css";
const services = () => (
<Layout>
<Seo title="Services" description="Blog site service page" />
<header id="page-title" className="jumbotron background">
<div className="container">
<div className="horizontal-center vertical-center">
<h1 className="article-title">Our Services</h1>
<h2 className="article-subtitle"><span>&#8220;</span>Don't watch the clock; do what it does. Keep going.<span>&#8221;</span></h2>
</div>
</div>
</header>
</Layout>
)
export default services
  • Create “menu.js” file in components folder
  • since we are using arrow fn we can git red of the curly braces and the return keyword too. (for all components and pages)
  • Add inline style for the menu component and inside here everything is JS (like CSS will look like JS only [CSSinJS]) -here we are using flexbox and emmet to use emmet abbreviation (like: li*4 and press tab)
  • add tag inside of li tag
  • we will add blog menu later inside of the menu component
import { Link } from 'gatsby'
import React from 'react'
const Menu = () => (
<div style={{
background: '#e5ebea',
paddingTop: '10px',
}}>
<ul style={{
listStyle: 'none',
display: 'flex',
justifyContent: 'space-evenly',
marginBottom: 0,
}}>
<li>
<Link to="/" >Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/services">Services</Link>
</li>
<li>
<Link to="/blog">Blog</Link>
</li>
</ul>
</div>
)
export default Menu
  • Then insert your the Menu in your layout or it will not show it on refresh
  • Put the right below in the layout.js file
/**
* Layout component that queries for data
* with Gatsby's useStaticQuery component
*
* See: https://www.gatsbyjs.com/docs/use-static-query/
*/
import * as React from "react"
import PropTypes from "prop-types"
import { useStaticQuery, graphql } from "gatsby"
import Header from "./header"
import Menu from "./menu"
import "./layout.css"
const Layout = ({ children }) => {
const data = useStaticQuery(graphql`
query SiteTitleQuery {
site {
siteMetadata {
title
}
}
}
`)
return (
<>
<Header siteTitle={data.site.siteMetadata?.title || `Title`} />
<Menu />
<div>
<main>{children}</main>
<footer
style={{
padding: `1rem`,
backgroundColor: '#e5ebea',
}}
>
© {new Date().getFullYear()}, Built with
{` `}
<a href="https://www.gatsbyjs.com">Gatsby</a>
</footer>
</div>
</>
)
}
Layout.propTypes = {
children: PropTypes.node.isRequired,
}
export default Layout
  • Explain about the component based architecture of react in brief
  • If you want to change common styles then you have to do it layouts.css file (ex: changing anchor tag styles etc)
html {
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
font: 112.5%/1.45em georgia, serif, sans-serif;
box-sizing: border-box;
overflow-y: scroll;
}
body {
margin: 0;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: hsla(0, 0%, 0%, 0.8);
font-family: georgia, serif;
font-weight: normal;
word-wrap: break-word;
font-kerning: normal;
-moz-font-feature-settings: "kern", "liga", "clig", "calt";
-ms-font-feature-settings: "kern", "liga", "clig", "calt";
-webkit-font-feature-settings: "kern", "liga", "clig", "calt";
font-feature-settings: "kern", "liga", "clig", "calt";
}
article,
aside,
details,
figcaption,
figure,
footer,
header,
main,
menu,
nav,
section,
summary {
display: block;
}
audio,
canvas,
progress,
video {
display: inline-block;
}
audio:not([controls]) {
display: none;
height: 0;
}
progress {
vertical-align: baseline;
}
[hidden],
template {
display: none;
}
a {
background-color: transparent;
-webkit-text-decoration-skip: objects;
color: #333;
text-decoration: none;
}
a:active,
a:hover {
outline-width: 0;
}
abbr[title] {
border-bottom: 1px dotted hsla(0, 0%, 0%, 0.5);
cursor: help;
text-decoration: none;
}
b,
strong {
font-weight: inherit;
font-weight: bolder;
}
dfn {
font-style: italic;
}
h1 {
margin-left: 0;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
color: inherit;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
font-weight: bold;
text-rendering: optimizeLegibility;
font-size: 2.25rem;
line-height: 1.1;
}
mark {
background-color: #ff0;
color: #000;
}
small {
font-size: 80%;
}
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
img {
border-style: none;
max-width: 100%;
margin-left: 0;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
}
svg:not(:root) {
overflow: hidden;
}
code,
kbd,
pre,
samp {
font-family: monospace;
font-size: 1em;
}
figure {
margin-left: 0;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
}
hr {
box-sizing: content-box;
overflow: visible;
margin-left: 0;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: calc(1.45rem - 1px);
background: hsla(0, 0%, 0%, 0.2);
border: none;
height: 1px;
}
button,
input,
optgroup,
select,
textarea {
font: inherit;
margin: 0;
}
optgroup {
font-weight: 700;
}
button,
input {
overflow: visible;
}
button,
select {
text-transform: none;
}
[type="reset"],
[type="submit"],
button,
html [type="button"] {
-webkit-appearance: button;
}
button::-moz-focus-inner {
border-style: none;
padding: 0;
}
button:-moz-focusring {
outline: 1px dotted ButtonText;
}
fieldset {
border: 1px solid silver;
padding: 0.35em 0.625em 0.75em;
margin-left: 0;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
}
legend {
box-sizing: border-box;
color: inherit;
display: table;
max-width: 100%;
padding: 0;
white-space: normal;
}
textarea {
overflow: auto;
}
[type="checkbox"],
[type="radio"] {
box-sizing: border-box;
padding: 0;
}
[type="number"]::-webkit-outer-spin-button {
height: auto;
}
[type="search"] {
-webkit-appearance: textfield;
outline-offset: -2px;
}
[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-input-placeholder {
color: inherit;
opacity: 0.54;
}
::-webkit-file-upload-button {
-webkit-appearance: button;
font: inherit;
}
* {
box-sizing: inherit;
}
*:before {
box-sizing: inherit;
}
*:after {
box-sizing: inherit;
}
h2 {
margin-left: 0;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
color: inherit;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
font-weight: bold;
text-rendering: optimizeLegibility;
font-size: 1.62671rem;
line-height: 1.1;
}
h3 {
margin-left: 0;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
color: inherit;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
font-weight: bold;
text-rendering: optimizeLegibility;
font-size: 1.38316rem;
line-height: 1.1;
}
h4 {
margin-left: 0;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
color: inherit;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
font-weight: bold;
text-rendering: optimizeLegibility;
font-size: 1rem;
line-height: 1.1;
}
h5 {
margin-left: 0;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
color: inherit;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
font-weight: bold;
text-rendering: optimizeLegibility;
font-size: 0.85028rem;
line-height: 1.1;
}
h6 {
margin-left: 0;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
color: inherit;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
font-weight: bold;
text-rendering: optimizeLegibility;
font-size: 0.78405rem;
line-height: 1.1;
}
hgroup {
margin-left: 0;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
}
ul {
margin-left: 1.45rem;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
list-style-position: outside;
list-style-image: none;
}
ol {
margin-left: 1.45rem;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
list-style-position: outside;
list-style-image: none;
}
dl {
margin-left: 0;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
}
dd {
margin-left: 0;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
}
p {
margin-left: 0;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
}
pre {
margin-left: 0;
margin-right: 0;
margin-top: 0;
margin-bottom: 1.45rem;
font-size: 0.85rem;
line-height: 1.42;
background: hsla(0, 0%, 0%, 0.04);
border-radius: 3px;
overflow: auto;
word-wrap: normal;
padding: 1.45rem;
}
table {
margin-left: 0;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
font-size: 1rem;
line-height: 1.45rem;
border-collapse: collapse;
width: 100%;
}
blockquote {
margin-left: 1.45rem;
margin-right: 1.45rem;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
}
form {
margin-left: 0;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
}
noscript {
margin-left: 0;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
}
iframe {
margin-left: 0;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
}
address {
margin-left: 0;
margin-right: 0;
margin-top: 0;
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
padding-top: 0;
margin-bottom: 1.45rem;
}
b {
font-weight: bold;
}
strong {
font-weight: bold;
}
dt {
font-weight: bold;
}
th {
font-weight: bold;
}
li {
margin-bottom: calc(1.45rem / 2);
}
ol li {
padding-left: 0;
}
ul li {
padding-left: 0;
}
li > ol {
margin-left: 1.45rem;
margin-bottom: calc(1.45rem / 2);
margin-top: calc(1.45rem / 2);
}
li > ul {
margin-left: 1.45rem;
margin-bottom: calc(1.45rem / 2);
margin-top: calc(1.45rem / 2);
}
blockquote *:last-child {
margin-bottom: 0;
}
li *:last-child {
margin-bottom: 0;
}
p *:last-child {
margin-bottom: 0;
}
li > p {
margin-bottom: calc(1.45rem / 2);
}
code {
font-size: 0.85rem;
line-height: 1.45rem;
}
kbd {
font-size: 0.85rem;
line-height: 1.45rem;
}
samp {
font-size: 0.85rem;
line-height: 1.45rem;
}
abbr {
border-bottom: 1px dotted hsla(0, 0%, 0%, 0.5);
cursor: help;
}
acronym {
border-bottom: 1px dotted hsla(0, 0%, 0%, 0.5);
cursor: help;
}
thead {
text-align: left;
}
td,
th {
text-align: left;
border-bottom: 1px solid hsla(0, 0%, 0%, 0.12);
font-feature-settings: "tnum";
-moz-font-feature-settings: "tnum";
-ms-font-feature-settings: "tnum";
-webkit-font-feature-settings: "tnum";
padding-left: 0.96667rem;
padding-right: 0.96667rem;
padding-top: 0.725rem;
padding-bottom: calc(0.725rem - 1px);
}
th:first-child,
td:first-child {
padding-left: 0;
}
th:last-child,
td:last-child {
padding-right: 0;
}
tt,
code {
background-color: hsla(0, 0%, 0%, 0.04);
border-radius: 3px;
font-family: "SFMono-Regular", Consolas, "Roboto Mono", "Droid Sans Mono",
"Liberation Mono", Menlo, Courier, monospace;
padding: 0;
padding-top: 0.2em;
padding-bottom: 0.2em;
}
pre code {
background: none;
line-height: 1.42;
}
code:before,
code:after,
tt:before,
tt:after {
letter-spacing: -0.2em;
content: " ";
}
pre code:before,
pre code:after,
pre tt:before,
pre tt:after {
content: "";
}
@media only screen and (max-width: 480px) {
html {
font-size: 100%;
}
}
  • in the pages folder create a new folder called “2022–01–14-post-one”.
  • inside of that folder create a new markdown file called “index.md”
---
path: "/post-one"
date: "2021-11-15"
title: "My first Gatsby post"
author: "Ameen Shaikh"
---
This is my very **first** blog post in Gatsby
  • In this markdown we will have posts which will be content
  • we also have a frontmatter, which will go inbetween 2 triple hypes/dashes( — -)
---
{content}
---
  • let’s create another blog post with front matter like before.
  • create a new folder called “2021–11–15-post-two” and inside this create “index.md” file
---
path: "/post-two"
date: "2021-11-15"
title: "My Second Gatsby post"
author: "John Doe"
---
This is my very second blog post in Gatsby
  • Once everything is configured & you created client website, you can tell them to do create a blog post (DO NOT COVER)
  • Now we need to create a way to access these pages
  • npm i gatsby-source-filesystem
  • This allows us to work with our local data (used to query our blogs from blog system)
  • npm i gatsby-transformer-remark
  • To transform our blog posts that are written in markdown (.md) files into HTML for rendering.
  • npm i gatsby-plugin-catch-links
  • It will intercept links for markdown and other non react pages and does a client side push state to avoid the browser having to refresh the page
  • show “package.json” file that these plugins have been installed
  • after installing these plugins we need to configure these files
  • so in the plugins array add these below
plugins: [
`gatsby-plugin-react-helmet`,
`gatsby-plugin-image`,
`gatsby-plugin-catch-links`,
{
resolve: `gatsby-source-filesystem`,
options: {
name: `images`,
path: `${__dirname}/src/images`,
},
},
{
resolve: `gatsby-source-filesystem`,
options: {
name: `pages`,
path: `${__dirname}/src/pages`,
},
},
`gatsby-transformer-remark`,
......
......
......
]
  • run the script agian and make sure that you don’t have any errors
  • Till now except blogs everything is eorking fine
  • we have a tool called “graphical”
  • url: ‘localhost:8000/___graphql’
  • this allows us to write graphQL queries
    ex:
{
allMarkdownRemark {
edges{
node {
id
}
}
}
}
  • To get all the files in the pages folder
  • this will give data object that has all the files
  • Edge is and array of our nodes and our nodes are our files
  • id is complete path and file name of each file
  • when we use our query to get our markdown file we will use markdown-transformer
  • frontmatter will give us frontmatter
  • excerpt will give us the actual content
  • so, we are using graphQL to grab our markdown files. This is what we will do in our markdown template
  • Let’s work on blog index page to show listing of blogs/posts
  • create a new page/file called ‘blog.js’
import { graphql, Link } from 'gatsby';
import React from 'react'
import Layout from "../components/layout"
import Seo from "../components/seo"
import "./common.css";
const blogPage = ({data}) => (
<Layout>
<Seo title="Blog" description="Latest posts" />
<div className="blog">
<h1>Latest Posts</h1>
{ data.allMarkdownRemark.edges.map(post => (
<div className="blog-container" key={post.node.id}>
<h3 className="">{post.node.frontmatter.title}</h3>
<small className="">
Posted by {post.node.frontmatter.author} on {post.node.frontmatter.date}
</small>
<div className="blog-details-btn">
<Link to={post.node.frontmatter.path}>Read More</Link>
</div>
</div>
))
}
</div>
</Layout>
)
export const pageQuery = graphql`
query BlogIndexQuery {
allMarkdownRemark {
edges{
node {
id
frontmatter {
path
title
date
author
}
excerpt
}
}
}
}
`;
export default blogPage
  • so now in blog pages we can see all the posts
  • if we click on ‘Read more’ then we will get 404 error
  • so to resolve this we need to create a template
  • Create a folder in the source called “templates” and inside that create ‘blog-post.js’ file
  • get the post from ‘markdownRemark’
  • we will create a graphQL qury to get the ‘markdownRemark’ and other related data
import { graphql, Link } from 'gatsby';
import React from 'react';
import "./blog-post.css";
export default function Template ({data}) {
const post = data.markdownRemark;
return(
<div className="blog-post">
<Link to="/blog"> <span>&#8592;</span> Go Back</Link>
<hr />
<h1>
{post.frontmatter.title}
</h1>
<h4>posted by <strong>{post.frontmatter.author}</strong> on <small>{post.frontmatter.date}</small></h4>
<div dangerouslySetInnerHTML={{__html: post.html}}></div>
</div>
)
}
export const postQuery = graphql`
query BlogPostByPath($path: String!) {
markdownRemark(frontmatter: { path: { eq: $path} }) {
html
frontmatter {
path
title
date
author
}
}
}
`
  • we will ise react’s dangerouslySetInnerHTML to set our HTML (i.e,
<div dangerouslySetInnerHTML={{__html: post.html}}></div>
  • so this will allow to actually have HTML markup inside of it
  • query has been added above
  • Now, we will get a 404 error because even though we created a template and query it doesn’t know what the ‘post-one’ is to get to that post.
  • we need to use createPageAPI
const path = require('path');exports.createPages = async function ({ actions, graphql }) {  const postTemplate = path.resolve('src/templates/blog-post.js')  const { data } = await graphql(`
query {
allMarkdownRemark {
edges{
node {
html
id
frontmatter {
path
title
date
author
}
}
}
}
}
`)
data.allMarkdownRemark.edges.forEach(edge => {
const slug = edge.node.frontmatter.path
actions.createPage({
path: slug,
component: postTemplate,
context: { slug: slug },
})
})
}
.jumbotron {
padding: 0 10p;
}
#page-title {
position: relative;
width: 100%;
color: white;
background-color: #1f4a6f;
font-family: "ubuntu", sans-serif;
overflow: hidden;
}
#title-image {
filter: alpha(opacity=80);
opacity: 0.8;
-moz-opacity: 0.8;
}
#page-title .container {
min-height: 70vh;
text-align: center;
padding: 3rem 1rem;
}
#page-title .article-title {
padding-bottom: 10px;
}
#page-title .article-title,
#page-title .article-subtitle {
text-shadow: 0px 0px 40px black;
}
.blog {
padding: 0 10px 10px 30px;
background-color: #e5ded8;
}
.blog h1 {
text-align: center;
padding: 20px 0 10px 0;
}
.blog .blog-container {
background: #fff;
border-radius: 5px;
box-shadow: hsla(0, 0, 0, .2) 0 4px 2px -2px;
font-family: "adelle-sans", sans-serif;
font-weight: 100;
margin: 48px auto;
width: 20rem;
margin: 0 auto;
padding: 1rem 1.5rem;
margin-bottom: 5px;
}
.blog .blog-container .blog-details-btn {
padding-top: 10px;
}
.blog .blog-container a {
color: #1f4a6f;
text-decoration: underline;
}
@media screen and (min-width: 480px) {
.blog .blog-container {
width: 28rem;
}
}
@media screen and (min-width: 767px) {
.blog .blog-container {
width: 40rem;
}
}
@media screen and (min-width: 959px) {
.blog .blog-container {
width: 50rem;
}
}
.blog-post {
padding: 10px 10px 10px 30px;
background-color: #e5ded8;
height: 100vh;
}
.blog-post a {
color: #1f4a6f;
}
Home page
Blog page
Blog details page

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store