🍅 automatoes.com

Create a Markdown Blog Post with Embeds in a Single Command

Usage: blog "a post with a youtube and egghead embed" -y "awftawftoyun" -e "Bawftyun"

Result: A markdown file properly titled with frontmatter and codesandbox/youtube/egghead embeds

I'll make a video sometime to walk through this entire process, but here's the gist of it:

I use this zsh function called blog:

# y:youtube c:codesandbox e:egghead
zparseopts -D -E -A opts y: c: e:

cd ~/projects/johnlindquist.com

local title="$(change -c title "$1")"
local slug="$(change "$1")"

# Use the array_of_lines technique in case node.js console more than 1 line of text
# array_of_lines=("${(@f)$(my_command)}")
array_of_lines=("${(@f)$(node ~/projects/blog/index.js "$title" \
  $(slug)
)}")

filePath=$array_of_lines[-1]

port=$(detect 8000)
code . -g "$filePath"
open "http://localhost:8000/${slug}"

# The port is available when it's the same as the requested port
if [ $port = 8000 ]
  then
  yarn develop
fi

Which triggers this node script:

#!/usr/bin/env node

const slugify = require("slugify")
const fs = require("fs-extra")
const { format } = require("date-fns")
const formatTitle = require("ap-style-title-case")
const cac = require("cac")
const cli = cac()
const path = require("path")

cli
  .command("[...title]")
  .option(
    "--codesandbox <codesandbox>",
    "Codesandbox slug",
    { type: String, default: "" }
  )
  .option("--youtube <youtube>", "Youtube slug", {
    type: String,
    default: "",
  })
  .option("--egghead <egghead>", "egghead slug", {
    type: String,
    default: "",
  })
  .action(([text], options) => {
    const { codesandbox, youtube, egghead } = options

    const slug = slugify(text, {
      replacement: "-", // replace spaces with replacement
      remove: /[*+~.()'"!:@,]/g, // regex to remove characters
      lower: true, // result in lower case
    })

    const title = formatTitle(text)

    // console.log({ codesandbox, youtube, egghead })

    const codesandboxBlock =
      codesandbox && `<Codesandbox slug="${codesandbox}"/>`
    const youtubeBlock =
      youtube && `<YoutubeEmbed slug="${youtube}"/>`
    const eggheadBlock =
      egghead && `<EggheadEmbed slug="${egghead}"/>`

    const content = `---
slug: ${slug}
title: ${title}
date: ${format(new Date(), "YYYY-MM-DD HH:MM")}
published: false
category: ['']
---

${codesandboxBlock || ""}
${youtubeBlock || ""}
${eggheadBlock || ""}
`

    // console.log(content)
    const localPath = `content/posts/${slug}.md`
    const filePath = path.resolve(process.cwd(), localPath)

    ;(async () => {
      try {
        await fs.writeFile(filePath, content, {
          flag: "wx",
        })
        console.log("Succesfully written " + filePath)
        console.log(localPath)
      } catch (error) {
        console.log(error)
        console.log("file " + filePath + " already exists")
      }
    })()
  })

cli.parse()

Tags

Contributor: [John Lindquist]

Referred in

edit
Create a Markdown Blog Post with Embeds in a Single Command