Andrew JD Hudson

Photo of Andrew JD Hudson

Getting in the way of writing

345

Current Process when attempting to write a blog post

I have a need to write a blog so I need to jump through a number of hoops before I can do it.

  1. Update Astro because that is always a thing that is nice and shiny and makes me feel good.
  2. Start the local server, open up the url in Chrome
  3. Find an old blog post that I can copy to get the new one started. This takes ages and takes mental energy.
  4. Set the title and date of the post, as well as optional tags. This takes more energy.
  5. Finally get round to starting to type the content of the blog post only to run out of mental energy and stop because the initial excitement about sharing something with the world has been reduced to a mear trickle and other things now seem more pressing.
  6. Convert the blog post into draft mode
  7. Commit the code to Git because why not
  8. Never update the blog post again and leave it forever more in draft unfinished mode.

Other distractions

  1. The design of my site
  2. the world outside
  3. the configuration of VS Code that I am using for this repository
  4. life, the internet, everything outside

Is there a better way?

Of course the above is shit and this is why I have not written anything good on this site for a long time. The pressures from all sides are preventing me.

A better way:

  1. Have a script that creates a new blog post from a template e.g. with todays date, an option to enter a title, then once that is done it takes me directly to the new file, with the terminal running the local server and the browser pointing to the newly created page.
  2. This would prevent me from fiddling with anything that is not the content of the blog. And hopefully it would enable me to create better posts going forwards.

Final Solution

I have created a zx script and I start it with make create on the terminal. This then gives me the option of what I would like to call the blog post, then fires up the browser with the new url, fires up the local dev server, and also more importantly it focuses on the new markdown file in VS Code on the correct line to start typing straight away.

script.mjs
import {
autocomplete,
isCancel,
note,
outro,
select,
text,
} from "@clack/prompts";
import { Temporal } from "@js-temporal/polyfill";
import { $ } from "execa";
import fs from "fs-extra";
const openCodeInCodeEditor = async (newFile) => {
const editor = "zed"; // could also be vscode
await $`${editor} ${newFile}`;
// await $`${editor} ${newDirectory}/index.html:2:5 -g`;
// -g does not work with zed
// 8th line. first character 8:1
await $`${editor} ${newFile}:8:8`;
return;
};
const showSuccessMessage = () => {
note(
`opening Code Editor to edit the code
opening default browser on http://localhost:8888
`,
"Success",
);
};
const runDevServer = async () => {
await $`npm run dev -- --open`;
};
const runDevServerWithUrl = async (url) => {
console.log("need to open browser at url ", url);
await openSiteInBrowser(url);
await $`npm run dev`;
};
const openSiteInBrowser = async (url) => {
return await $({
shell: true,
})`open -a "Google Chrome Canary" "${url}"`;
};
async function main() {
console.clear();
// Which Path to take?
// 1. [x] Create new Post
// 2. [ ] Edit Existing Post
const selection = await select({
message: "What do you want to do first?",
initialValue: "create",
maxItems: 1,
options: [
{
value: "create",
label: "Create",
},
{
value: "edit",
label: "Edit",
},
],
});
if (selection === "edit") {
const files = await fs.readdir("./src/content/blog");
const filteredFiles = files.filter((file) => file.includes(".md"));
const postToEdit = await autocomplete({
message: "Select the demo you want to develop",
initialValue: "",
maxItems: 1,
options: filteredFiles.map((post) => ({
value: post,
label: post,
})),
});
const postFile = `src/content/blog/${postToEdit}`;
const url = `http://localhost:8888/blog/${postToEdit.replace(".md", "")}`;
try {
// AHTODO: can this be done in serial?
await Promise.all([
runDevServerWithUrl(url),
openCodeInCodeEditor(postFile),
showSuccessMessage(),
]);
} catch (error) {
console.error(error);
}
}
// if (selection === "build") {
// const files = await fs.readdir("./src/demos");
// const demosSelection = await autocomplete({
// message: "Select the demo you want to build",
// initialValue: "",
// maxItems: 1,
// options: files.map((demo) => ({
// value: demo,
// label: demo,
// })),
// });
// const selectedDirectory = `src/demos/${demosSelection}`;
// try {
// // AHTODO: can this be done in serial?
// await runBuild(selectedDirectory);
// await runPreview(selectedDirectory);
// } catch (error) {
// console.error(error);
// }
// }
if (selection === "create") {
const postTitle = await text({
message: "Enter your post title (letters and spaces only)",
placeholder: "a new post",
// initialValue: "a new post",
validate: (value) => {
if (!value) {
return "Please enter a Post title.";
}
if (!/^[a-zA-Z0-9- ]+$/.test(value)) {
return "Name can only contain letters, numbers, and hyphens ";
}
const newFile = `src/content/blog/${value.trim().replaceAll(" ", "-")}.md`;
if (fs.existsSync(newFile)) {
return "file exists already, edit the title and try again";
}
// TODO: validate that there is a minimum of 3 letters
return undefined;
},
});
if (!isCancel(postTitle)) {
note(`Valid title: ${postTitle}`, "Success");
}
const trimmedTitle = postTitle.trim().replaceAll(" ", "-");
const newFile = `src/content/blog/${trimmedTitle}.md`;
await createPostFile(newFile, postTitle);
try {
// AHTODO: can this be done in serial?
await Promise.all([
runDevServer(trimmedTitle),
openCodeInCodeEditor(newFile),
showSuccessMessage(),
]);
} catch (error) {
console.error(error);
}
}
outro("all done");
}
const createPostFile = async (newFile, title) => {
try {
if (!fs.existsSync(newFile)) {
const date = Temporal.Now.plainDateISO();
const { day, month, year } = Temporal.PlainDate.from(date);
const pubDate = `${year}-${month}-${day}`;
const content = `---
title: "${title}"
date: ${pubDate}
draft: false
tags: [""]
---
`;
await fs.writeFile(newFile, content);
note("success! New Post created");
} else {
throw new Error("post exists already. Show error");
}
} catch (err) {
console.error(err);
}
};
main().catch(console.error);
← Back to all blog posts
Edit this post on Github