<main id="app" class="wrapper">
	<aside id="aside" class="sticky top-0 ml-8 pt-16">
				
	</aside>
	<div class="max-w-2xl content mt-32" id="content">
</main>

html {
	height: 100%;
}


body {
	display: flex;
	flex-direction: column;
	margin: auto;
  background-color: white;
	font-family: 'Cabin', sans-serif;
  font-weight: 400;
  line-height: 1.65;
  color: #333;
	font-size: 20px;
	
	&::before {
		content: "";
		position: fixed;
		top: 0; 
		left: 0;
		width: 100%; 
		height: 100%;  
		opacity: .05; 
		z-index: -1;
		background: url("https://static.thenounproject.com/png/2590971-200.png");
		background-size: 200px 200px;
		background-repeat: repeat;
		background-position: center center;
	}
}


h1, h2, h3, h4, h5 {
	font-family: 'Oswald', sans-serif;
  margin: 2.75rem 0 1.05rem;
  font-weight: 400;
  line-height: 1.15;
}

h1 {
  font-size: 3.052em;
}

h2 {font-size: 2.441em;}

h3 {font-size: 1.953em;}

h4 {font-size: 1.563em;}

h5 {font-size: 1.25em;}

.wrapper {
	margin: 0 auto;
	display: grid;
  padding: 10px;
  grid-template-columns: 300px auto;
  grid-gap: 30px;
	align-items: flex-start;
}
View Compiled

async function fetchAndParseMarkdown() {
  const url = 'https://gist.githubusercontent.com/lisilinhart/e9dcf5298adff7c2c2a4da9ce2a3db3f/raw/2f1a0d47eba64756c22460b5d2919d45d8118d42/red_panda.md'
  const response = await fetch(url)
  const data = await response.text()
  const htmlFromMarkdown = marked(data, { sanitize: true });
  return htmlFromMarkdown
}


function generateLinkMarkup($contentElement) {
	const headings = [...$contentElement.querySelectorAll('h1, h2')]
	const parsedHeadings = headings.map(heading => {
		return {
			title: heading.innerText,
			depth: heading.nodeName.replace(/\D/g,''),
			id: heading.getAttribute('id')
		}
	})
	const htmlMarkup = parsedHeadings.map(h => `
	<li class="${h.depth > 1 ? 'pl-4' : ''}">
		<a href="#${h.id}">${h.title}</a>
	</li>
	`)
	const finalMarkup = `
		<ul>${htmlMarkup.join('')}</ul>
	`
	return finalMarkup
}

async function init() {
	const $main = document.querySelector('#content');
	const $aside = document.querySelector('#aside');
	const htmlContent = await fetchAndParseMarkdown();
	$main.innerHTML = htmlContent
	const linkHtml = generateLinkMarkup($main);
	$aside.innerHTML = linkHtml	
}

init();
View Compiled

External CSS

  1. https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/1.9.1/tailwind.min.css
  2. https://fonts.googleapis.com/css?family=Cabin:400,500,600,700
  3. https://fonts.googleapis.com/css?family=Oswald:200,300,400,500,600,700

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/marked/1.1.1/marked.min.js
  2. https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.min.js