John Polacek

Chicago Web Developer

Engineering manager and frontend lead at Howl

My product recommendations at shop.howl.me

Shipping open source on Github

Follow me at @johnpolacek

Growth Areas for a Software Developer

Originally published on 9/12/2020
5 Growth Areas for a Software Developer

As I’ve been doing one-on-ones, I wanted to create some better criteria to guide our discussions. I wrote up a markdown document with some thoughts about the skills and mindset of a software developer, and examples of things to do and not do.

Through the power of Next.js and MDX, I turned that markdown file into a web page at growth-areas-for-a-software-developer.vercel.app. See the code on GitHub.

Here’s how I did it. First, we’ll start from the basic Next.js with MDX Example as I’ve written about in my How to Use Your README.md on Your Project’s Docs post.

With Next.js, use a custom _document.js file in the pages directory to allow us to add things like the lang attribute, meta tags and so forth.

pages/_document.js

import Document, { Html, Head, Main, NextScript } from "next/document"
export default class MyDocument extends Document {
render() {
return (
<Html lang="en">
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}

Next, we can set up our index page to load our README markdown content and render it with MDXProvider.

pages/index.js

import { MDXProvider } from "@mdx-js/react"
import Head from "../components/Head"
import ReadMe from "../README.md"
const IndexPage = () => (
<>
<Head />
<MDXProvider>
<ReadMe />
</MDXProvider>
</>
)
export default IndexPage

The Head component is for setting all the properties of the web page’s document head such as the page title and meta tags.

components/Head.js

import Head from "next/head"
const url = "/"
const title = "Growth Areas for a Software Developer"
const description = "A list of areas to focus on in and examples to follow in order to grow your career as a software developer."
const twitter = "@johnpolacek"
const imageUrl = "https://growth-areas-for-a-software-developer.vercel.app/screenshot.png"
const imageAlt = "5 Growth Areas for a Software Developer"
const DocHead = () => (
<>
<Head>
<title>{title}</title>
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
<link rel="canonical" href={url} />
<meta name="description" content={description} />
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
{imageUrl && <meta property="og:image" content={imageUrl} />}
{imageAlt && <meta property="og:image:alt" content={imageAlt} />}
<meta property="og:url" content={url} />
<meta name="twitter:card" content={imageUrl ? "summary_large_image" : "summary"} />
<meta name="twitter:site" content={twitter} />
<meta name="twitter:creator" content={twitter} />
<meta name="twitter:title" content={title} />
<meta name="twitter:description" content={description} />
{imageUrl && <meta property="twitter:image" content={imageUrl} />}
{imageAlt && <meta property="twitter:image:alt" content={imageAlt} />}
</Head>
</>
)
export default DocHead

Ok now to make it look fancy. Next.js has built-in support for CSS Modules so we can follow their next-css example and add _app.js and styles.css. The markdown output is basic html, so we don’t have any class names to use as selectors. Time to use that CSS cascade and selector knowledge.

style.css

:root {
--shade1: #304DA5;
--shade2: #3656B5;
--shade3: #3A5CC4;
--shade4: #3F63D0;
--space-1: 8px;
--space-2: 16px;
--space-3: 32px;
--space-4: 48px;
--space-5: 64px;
--space-6: 96px;
}
body {
padding: 0 0 var(--space-4);
margin: 0;
color: white;
font-family: avenir next,avenir,Calibri,Candara,Segoe,Segoe UI,Optima,Arial,sans-serif;
text-align: center;
font-size: 24px;
}
body > div {
display: flex;
justify-content: center;
flex-wrap: wrap;
padding-bottom: var(--space-6);
}
ul {
list-style-type: none;
margin: 0;
padding: 0;
}
body > div > ul > li {
margin: 0;
padding: var(--space-4) 0;
}
body, body > div > ul > li:nth-child(6) {
background: var(--shade1);
}
body > div > ul > li:nth-child(1),body > div > ul > li:nth-child(5) {
background: var(--shade2);
}
body > div > ul > li:nth-child(2), body > div > ul > li:nth-child(4) {
background: var(--shade3);
}
body > div > ul > li:nth-child(3) {
background: var(--shade4);
}
body > div > h2 {
padding-top: var(--space-4);
}
body > div > p {
font-size: 18px;
}
body > div > p a {
color: white;
font-weight: 500;
}
h1, h2 {
z-index: 9999;
}
h1 {
width: 100%;
padding: var(--space-6) var(--space-4);
font-weight: 600;
font-size: 72px;
line-height: 1.2;
max-width: 720px;
}
h2 {
border-bottom: solid 1px rgba(255,255,255,.2);
width: 100%;
max-width: 360px;
padding-bottom: var(--space-1);
margin: var(--space-3) auto var(--space-4);
}
ul ul li {
display: flex;
flex-wrap: wrap;
justify-content: center;
padding-bottom: var(--space-4);
}
p {
width: 100%;
padding-bottom: var(--space-1);
}
blockquote {
font-weight: bold;
font-size: 18px;
font-style: italic;
background: white;
padding: var(--space-2) var(--space-3);
width: 300px;
margin: 0 var(--space-2);
border-radius: 8px;
color: #222;
margin-bottom: var(--space-3);
}
blockquote blockquote {
padding: 0;
margin: 0;
font-size: 18px;
font-style: normal;
font-weight: normal;
}
a {
color: var(--shade4);
}
body > div > ul > li blockquote {
color: var(--shade3);
}
body > div > ul > li blockquote blockquote {
color: #222;
}
@media only screen and (max-width: 420px) {
h1 {
font-size: 48px;
}
blockquote {
width: 240px;
}
}