Page 3

Been traveling a lot lately and got behind on trying out new fonts so I’ll just post one every Friday until I’m back on my one a month schedule.

Ring Angle by Isolatype is a fun, hand drawn font that would be good for kids books or projects. It’s free for personal use and includes an italic style. I especially like the alternate characters (like the R, g, and A above)!

Download at Font Space or buy at Creative Fabrica.

I don’t download a ton of script fonts but I’m really into Party Attack by NihStudio, maybe because it has a bolder, blockier feel than most. While you’re downloading, don’t miss their gallery of sample usages in menus, invitations, and more. Free for personal use only.

Download at 1001 Fonts or buy at Creative Fabrica.

TIL: Figma Edition

Shift + 2 has completely changed my relationship with Figma. Zoom right to whatever object you have selected. No more tediously zooming in and out and scrolling back and forth trying to center.

Thank you Figma shortcuts.

Package Publishing Reading & Resources

I have big plans in the works to overhaul a few projects and, to prep for that, I’ve been doing a lot of reading up on different approaches to publishing JavaScript packages. These are a few resources I’ve found particularly useful and informative.

  • How to Publish an Updated Version of an npm Package – Cloud Four - I’ve used different tools to automate releases in the past but had no idea what they were doing under the hood. This article walks through creating a release and publishing to npm and Git with detailed explanations at every step. It’s a great starting point since understanding the manual process makes evaluating different automated strategies a lot easier.
  • Automate npm publishing with GitHub Actions, proper changelog, and release notes - I'm looking for a solution that includes independently versioned monorepos so this guide isn't a perfect fit. However, using GitHub Actions to manually trigger a release and enter the correct version bump (major, minor, patch, etc.) is a really clever approach.
  • Release Workflow | Yarn - Package Manager - Yarn's release workflow for monorepos is an experimental feature so I’m holding off for now but I hope it pans out. The section on deferred versioning and record keeping is especially intriguing.
  • Tools! Trying to figure out which of these options would best serve my needs:
    • semantic-release - My current tool of choice. semantic-release depends on commit messages that follow Angular's commit message conventions for versioning. Unfortunately, it doesn't play nice with monorepos (for more details, here's a little extra credit reading The chronicles of semantic-release and monorepos).
    • Auto - Intuit - Automates releases based on pull request labels. I used this at a previous job and appreciated that it didn't require linting commit messages or any extra effort from contributors. The downside, Lerna is a must for use with monorepos.
    • Release It! - This seems promising. A CLI tool that can be used in interactive or continuous integration mode. The big appeal for me is a Yarn workspaces specific plugin.

Finally, recommendations are welcome so here’s my brief. I want to combine multiple packages that currently live in separate repos into a single monorepo using Yarn workspaces. Ideally, I’d like to independently version the packages without adding Lerna and use GitHub Actions for CI/CD. If you have a similar setup, let me know what's worked for you.

Creative Market - Explore the World's Marketplace for Design
Advertisement
Creative Market - Explore the World's Marketplace for Design
Advertisement

Okay. It’s 2023. I just copied all the font release Tweets I’ve ever bookmarked on Twitter just in case that feature suddenly disappears. Let’s recommend some downloads.

Liquidie by Forberas is a fluid, hand drawn font. It’s free for personal use only and includes upper and lower case characters.

Download at Font Space or buy at Creative Market.

Finally moving away from the sixties inspired font recommendations.

Rocker Squad by Letterara is a thick, punk rock looking hand drawn font. Free for personal use only. 

Download at Font Space or buy at Creative Fabrica.

These first Friday font recommendations are increasingly any day of the week and exclusively sixties inspired font recommendations. In keeping with that, it’s a perfect Wednesday for downloading Groovy Daisy by Jimtype Studio. It’s free for personal use only and is, indeed, very groovy.

Download at Font Space.

Next.js and Tumblr as a CMS Part 4: Open Graph Images

Way back in my first post on using Next.js with Tumblr, I mentioned getting more control over my blog as one of the big motivations for the switch. So, I thought I’d wrap up by going over a couple of the specific things I meant by that: generating Open Graph images and adding syntax highlight to code blocks.

This was originally intended as one post but it got a little long and I’m a little slow so I’ll start with Open Graph images.

Open Graph images are the preview images you’ve probably seen when sharing a link on a social media site like Twitter or Facebook. By default, Tumblr will display a generic image with the Tumblr logo and some themes might pull in your avatar or let you upload a custom image. However, there isn’t a good way to attach different images to different posts or to dynamically generate them. My goal was for each of my posts to have a unique, text-based image displaying its title or description and type.

Sample Open Graph sharing image

There are a lot of good articles on the topic but their instructions didn’t get me exactly what I wanted so I wound up picking and choosing to cobble my solution together. Dynamic Open Graph images with Next.js was so close but it uses next-api-og-image which uses chrome-aws-lambda under the hood and I couldn’t get it to work on Vercel. I even tried the suggestion to install an older version of chrome-aws-lambda but it just wouldn’t deploy. Generate Open Graph images for your static Next.js site generated images during the build process instead of on the fly but it introduced using Playwright which was invaluable. Those two articles were big influences on the code below.

Start by installing the necessary playwright packages:

yarn add playwright playwright-core playwright-aws-lambda

Next, in your post component, add the meta tag inside the next/head block:

<Head>
  <meta property="og:image" content={`${process.env.NEXT_PUBLIC_BASE_URL}/api/og-image?headline=${post.headline || post.summary}&type=${post.type}`} />
  ...
</Head>

Two things to note: 1) for convenience, I store my base URL as an environmental variable so you’ll probable need to replace NEXT_PUBLIC_BASE_URL and 2) we’ll be using query params to pass the post headline and type.

The content URL points to a route we’ll create in pages/api/og-image.js. I’ve truncated a lot of the HTML and CSS since those will depend on how you want your image to look:

const playwright = require('playwright-aws-lambda');

export default async function handler (req, res) {
  const html = `
    <html>
      <head>
        <meta charset="UTF-8">
        
        <style>
          *, *:after, *:before {
            box-spacing: border-box;
          }

          html {
            font: 8px 'museo-sans-rounded', sans-serif;
            line-height: 1.4;
          }

          body {
            background: #f4f4f4;
            margin: 0;
            padding: 2rem;
          }
          
          ...
        </style>
      </head>

      <body>
        <div class="og">
          ...

          <div class="og__type">
            <span>laurenashpole.com</span>  —  ${(req.query || {}).type || ''} post
          </div>

          <h1 class="og__headline">${(req.query || {}).headline || ''}</h1>
        </div>        
      </body>
    </html>
  `;

  if (process.env.NODE_ENV === 'development') {
    res.setHeader('Content-Type', 'text/html');
    return res.end(html);
  }

  const browser = await playwright.launchChromium({ headless: true });
  const page = await browser.newPage();
  await page.setViewportSize({ width: 1200, height: 630 });
  await page.goto('about:blank');
  await page.setContent(html, { waitUntil: 'networkidle' });
  const img = await page.screenshot({ type: 'png' });
  await browser.close();

  res.setHeader('Cache-Control', 's-maxage=31536000, stale-while-revalidate');
  res.setHeader('Content-Type', 'image/png');
  res.end(img);
}

Now, if you visit that URL while developing locally, you should see an HTML page so you can inspect and tweak your designs. In production, Playwright will launch a headless browser, open a new page and insert your HTML, and then take and return a PNG screenshot.

And that’s how I set up my Open Graph images. Next time I’ll actually finish the series with syntax highlighting for code blocks.