Skip to content

Instantly share code, notes, and snippets.

@estruyf
Last active March 2, 2023 21:14
Show Gist options
  • Save estruyf/a473a2e82ef27d2dc85a468cd1ee8d0c to your computer and use it in GitHub Desktop.
Save estruyf/a473a2e82ef27d2dc85a468cd1ee8d0c to your computer and use it in GitHub Desktop.
Front Matter - Open Graph
"frontMatter.taxonomy.contentTypes": [{
"name": "default",
"pageBundle": false,
"filePrefix": "yyyy-MM-dd",
"fields": [{
"title": "Title",
"name": "title",
"type": "string",
"required": true
},
{
"title": "Title (long)",
"name": "longTitle",
"type": "string"
},
{
"title": "Custom field",
"name": "customField",
"type": "customField"
},
{
"title": "Slug",
"name": "slug",
"type": "slug",
"required": true
},
{
"title": "Description",
"name": "description",
"type": "string",
"required": true
},
{
"title": "Publishing date",
"name": "date",
"type": "datetime",
"required": true
},
{
"title": "Modified date",
"name": "lastmod",
"type": "datetime"
},
{
"title": "Content preview",
"name": "preview",
"type": "image",
"default": "{{ogImage}}",
"required": true
},
{
"title": "Is in draft",
"name": "draft",
"type": "draft",
"default": false
},
{
"title": "Comments",
"name": "comments",
"type": "boolean",
"default": true
},
{
"title": "Tags",
"name": "tags",
"type": "tags",
"default": [],
"required": true
},
{
"title": "type",
"name": "type",
"type": "string",
"default": "post",
"hidden": true
}
]
}]

The Content preview field, is where I defined my custom {{ogImage}} placeholder. This is actually bound to a script. The moment the article gets created, it will trigger the default value property.

Custom placeholders are configured in the frontMatter.content.placeholders setting.

"frontMatter.content.placeholders": [{
"id": "ogImage",
"script": "./scripts/og-image.js",
"command": "~/.nvm/versions/node/v16.11.1/bin/node"
}]

The placeholder above is linked to a script. I also configured the command to the path of my node executable, because with NVM this can sometimes give some issues.

The scrip looks as follows:

//@ts-check
const nodeHtmlToImage = require('node-html-to-image')
const uuid = require('uuid')
const { format, parseJSON } = require('date-fns');
const html = `
<html>
<head>
<style>
body {
width: 1128px;
height: 600px;
}
</style>
<!-- Include external CSS, JavaScript or Fonts! -->
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
<link href="https://fonts.googleapis.com/css2?family=Nunito&display=swap" rel="stylesheet">
<style>
:root {
--tw-gradient-to: #ffe45e;
--tw-gradient-from: #c91980;
--tw-gradient-stops: var(--tw-gradient-from),var(--tw-gradient-to,rgba(201,25,128,0));
}
body {
background-color: #0E1521;
font-family: 'Nunito', sans-serif;
}
.profile-img {
box-shadow: var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);
background-image: linear-gradient(to bottom right,var(--tw-gradient-stops));
padding: .25rem;
border-radius: 9999px;
display: inline-flex;
}
.tweet-text {
font-weight: 800;
color: transparent;
font-size: 8rem;
line-height: 1;
-webkit-background-clip: text;
background-clip: text;
background-image: linear-gradient(to bottom right,var(--tw-gradient-stops));
}
.tweet-date, .secondary-text {
color: rgba(213,209,215);
}
.horizontal {
background-color: rgba(64,69,81);
width: 16.666667%;
height: .25rem;
margin-top: 1rem;
margin-bottom: 1rem;
}
</style>
</head>
<body>
<div class="p-4" style=" font-size: 20px; width: 1128px; height:600px;">
<div class="d-flex flex-column justify-content-center" style="margin-left: 20px; height:100%; width:100%; border-radius:50px;">
<div>
<div class="profile-img">
<div>
<img src="https://www.eliostruyf.com/images/eliostruyf_2022.jpg" class="rounded-circle" width="150px">
</div>
</div>
</div>
<span class="tweet-text my-2" style="font-size: 52px;">
{title}
</span>
<span class="tweet-date">
{date}
</span>
<div class="horizontal">
<div class="rounded-full inline-flex"></div>
</div>
<h4 class="secondary-text">Elio Struyf</h4>
<span class="secondary-text">@eliostruyf</span>
</div>
</div>
</body>
</html>
`;
const arguments = process.argv;
if (arguments && arguments.length > 0 && arguments[2]) {
const workspaceArg = arguments[2];
const filePath = arguments[3];
const title = arguments[4];
if (title) {
const parsedHtml = html.replace(`{title}`, title).replace(`{date}`, format(new Date(), "MMM dd, yyyy"));
const fileName = `${uuid.v4()}.png`;
// @ts-ignore
nodeHtmlToImage({
output: `${workspaceArg}/static/social/${fileName}`,
html: parsedHtml
})
.then(() => console.log(`/social/${fileName}`))
.catch(e => console.log(e?.message || e));
}
}

You don't have to use the placeholder of course, you can also use the postScript property/option. Nice thing about the placeholder is that whatever you return, it will automatically set it as the value of the field.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment