Skip to content

Instantly share code, notes, and snippets.

@rodydavis

rodydavis/example.md

Created Dec 21, 2020
Embed
What would you like to do?
Based on md2googleslides this will create a Amp Story from Markdown
---

![](/images/banner.jpeg){.background}

# Rody Davis

## Welcome to my site

This is built with Lit-Element, Parcel and Web Components!

---

{.background}

export function md2ampstory(src: string, meta: AmpMeta): string {
const story: AmpStory = {
title: meta.title,
pages: [],
};
// Create Story
const sections = src.split("---");
for (let i = 0; i < sections.length; i++) {
const section = sections[i];
if (section.trim().length < 1) continue;
const layers: AmpLayer[] = [];
let layer: AmpVerticalLayer;
for (const line of section.split("\n")) {
if (line.trim().length < 1) continue;
if (line.match(".background")) {
const element = elementMap(line);
if (element.kind === "image") {
const _layer: AmpLayer = { kind: "fill", element: element };
if (layer != null) {
layers.push(layer);
}
layers.push(_layer);
layer == null;
continue;
}
} else {
if (layer == null) {
layer = { kind: "vertical", elements: [] };
}
const element = elementMap(line);
layer.elements.push(element);
}
}
if (layer != null) {
layers.push(layer);
layer = null;
}
story.pages.push({ id: `page_${i}`, layers: layers });
}
return renderStory(story);
}
function renderStory(story: AmpStory): string {
// Render Story
let result: string[] = [];
result.push(
`<!DOCTYPE html>
<html ⚡>
<head>
<meta charset="utf-8" />
<title>${story.title}</title>
<link rel="canonical" href="pets.html" />
<meta
name="viewport"
content="width=device-width,minimum-scale=1,initial-scale=1"
/>
<style amp-boilerplate>
body {
-webkit-animation: -amp-start 8s steps(1, end) 0s 1 normal both;
-moz-animation: -amp-start 8s steps(1, end) 0s 1 normal both;
-ms-animation: -amp-start 8s steps(1, end) 0s 1 normal both;
animation: -amp-start 8s steps(1, end) 0s 1 normal both;
}
@-webkit-keyframes -amp-start {
from {
visibility: hidden;
}
to {
visibility: visible;
}
}
@-moz-keyframes -amp-start {
from {
visibility: hidden;
}
to {
visibility: visible;
}
}
@-ms-keyframes -amp-start {
from {
visibility: hidden;
}
to {
visibility: visible;
}
}
@-o-keyframes -amp-start {
from {
visibility: hidden;
}
to {
visibility: visible;
}
}
@keyframes -amp-start {
from {
visibility: hidden;
}
to {
visibility: visible;
}
}
</style>
<noscript
><style amp-boilerplate>
body {
-webkit-animation: none;
-moz-animation: none;
-ms-animation: none;
animation: none;
}
</style></noscript
>
<script async src="https://cdn.ampproject.org/v0.js"></script>
<script
async
custom-element="amp-video"
src="https://cdn.ampproject.org/v0/amp-video-0.1.js"
></script>
<script
async
custom-element="amp-story"
src="https://cdn.ampproject.org/v0/amp-story-1.0.js"
></script>
<link
href="https://fonts.googleapis.com/css?family=Oswald:200,300,400"
rel="stylesheet"
/>
<style amp-custom>
amp-story {
font-family: "Oswald", sans-serif;
color: #fff;
}
amp-story-page {
background-color: #000;
}
h1 {
font-weight: bold;
font-size: 2.875em;
font-weight: normal;
line-height: 1.174;
}
p {
font-weight: normal;
font-size: 1.3em;
line-height: 1.5em;
color: #fff;
}
q {
font-weight: 300;
font-size: 1.1em;
}
amp-story-grid-layer.bottom {
align-content: end;
}
amp-story-grid-layer.noedge {
padding: 0px;
}
amp-story-grid-layer.center-text {
align-content: center;
}
.wrapper {
display: grid;
grid-template-columns: 50% 50%;
grid-template-rows: 50% 50%;
}
.banner-text {
text-align: center;
background-color: #000;
line-height: 2em;
}
</style>
<style>
* {
text-shadow: 1px 1px black;
}
</style>
</head>
<body>
<!-- Cover page -->
<amp-story
standalone
title="${story.title}"
publisher="Rody Davis"
publisher-logo-src="images/banner.jpeg"
poster-portrait-src="images/banner.jpg"
>
`
);
for (const page of story.pages) {
result.push(`<amp-story-page id=${page.id}>`);
for (let i = 0; i < page.layers.length; i++) {
const layer = page.layers[i];
result.push(`<amp-story-grid-layer template="${layer.kind}">`);
if (layer.kind == "vertical" || layer.kind == "horizontal") {
for (const element of layer.elements) {
addElement(element, result);
}
} else if (layer.kind == "fill") {
addElement(layer.element, result);
}
result.push(`</amp-story-grid-layer>`);
}
result.push(`</amp-story-page>`);
}
result.push(
`</amp-story>
</body>
</html>
`
);
return result.join("");
}
function addElement(element: AmpElement, result: string[]) {
if (element.kind == "text") {
result.push(`<${element.tag}>${element.data}</${element.tag}>`);
}
if (element.kind == "image") {
result.push(`<amp-img
src="${element.src}"
width="${element.width}"
height="${element.height}"
layout="responsive">
</amp-img>`);
}
}
function elementMap(line: string): AmpElement {
line = line.trimLeft();
// Heading
if (line.startsWith("# ")) {
return { kind: "text", data: line.replace("# ", ""), tag: "h1" };
}
if (line.startsWith("## ")) {
return { kind: "text", data: line.replace("## ", ""), tag: "h2" };
}
if (line.startsWith("### ")) {
return { kind: "text", data: line.replace("### ", ""), tag: "h3" };
}
if (line.startsWith("#### ")) {
return { kind: "text", data: line.replace("#### ", ""), tag: "h4" };
}
if (line.startsWith("##### ")) {
return { kind: "text", data: line.replace("##### ", ""), tag: "h5" };
}
if (line.startsWith("###### ")) {
return { kind: "text", data: line.replace("##### ", ""), tag: "h6" };
}
// Image
if (line.startsWith("![")) {
let start: number, end: number;
for (let i = 0; i < line.length; i++) {
const char = line[i];
if (char == "(") {
start = i + 1;
}
if (char == ")") {
end = i;
}
}
if (start != undefined && end != undefined) {
return {
kind: "image",
src: `${line.substring(start, end)}`,
width: 720,
height: 1280,
};
}
}
// Fallback to Regular Text
return { kind: "text", data: line, tag: "p" };
}
export interface AmpMeta {
title: string;
}
interface AmpStory {
pages: AmpPage[];
title: string;
}
interface AmpPage {
id: string;
layers: AmpLayer[];
}
type AmpLayer =
| AmpVerticalLayer
| AmpHorizontalLayer
| AmpFillLayer
| AmpThirdsLayer;
interface AmpVerticalLayer {
kind: "vertical";
elements: AmpElement[];
}
interface AmpHorizontalLayer {
kind: "horizontal";
elements: AmpElement[];
}
interface AmpFillLayer {
kind: "fill";
element: AmpImageElement;
}
interface AmpThirdsLayer {
kind: "thirds";
upper: AmpElement[];
middle: AmpElement[];
lower: AmpElement[];
}
type AmpElement = AmpTextElement | AmpImageElement;
interface AmpTextElement {
kind: "text";
tag: string;
data: string;
}
interface AmpImageElement {
kind: "image";
src: string;
width: number;
height: number;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment