Chris Padilla/Blog

You can follow by RSS! (What's RSS?) Full posts list here.

    White Coat

    Woohoo!

    Celebrated several things these past few weeks — including Miranda's white coat ceremony!!

    Blog Post Syntax Highlighting

    I've added syntax highlighting to the blog! Long overdue. Here's how I made it happen:

    Setup

    This site is a Next.js app. The blog posts are generated with the built in Static Site Generation feature. For each post, I grab all the urls to render and then they are constructed at build time:

    import AlbumPage from '/components/albumPage';
    import { getAllPosts, getAlbumBySlug, getAlbums } from '../lib/api';
    import { getPostBySlug } from '../lib/markdownAccess';
    import PostPage from '/components/PostPage';
    import markdownToHtml from '../lib/markdownToHtml';
    
    // The Main Component
    export default function SlugPage({ post, album }) {
      if (post) return <PostPage post={post} />;
      if (album) return <AlbumPage album={album} />;
    }
    
    // Get static props - gather required page data based on page
    export async function getStaticProps({ params }) {
      
      // . . . 
      
      const post = getPostBySlug(params.slug, [...);
    
      if (post) {
        return {
          props: {
            post,
          },
        };
      }
    
      return {
        notFound: true,
      };
    }
    
    // Get the static paths for all posts and pages
    export async function getStaticPaths() {
      const posts = getAllPosts(['slug']);
      const albums = getAlbums();
      const slugs = [...albums, ...posts].map((contentObj) => contentObj.slug);
    
      return {
        paths: slugs.map((slug) => {
          return {
            params: {
              slug,
            },
          };
        }),
        fallback: 'blocking',
      };
    }

    The post object contains the raw markdown and meta data for the page. All of the site's pages are built from that markdown and are rendered to JSX through this component:

    import markdownStyles from './markdown-styles.module.css';
    import Markdown from 'markdown-to-jsx';
    import Link from 'next/link';
    import Image from 'next/image';
    import NextLink from './NextLink';
    
    export default function PostBody({ content }) {
      return (
        <div className="markdown">
          <Markdown
            options={{
              overrides: {
                a: NextLink,
                img: BlogImage,
              },
            }}
          >
            {content}
          </Markdown>
        </div>
      );
    }
    
    // const BlogImage = (props) => <Image {...props} width={800} layout="fill" />;
    const BlogImage = (props) => (
      <a href={props.src} target="_blank" rel="noopener noreferrer">
        <img {...props} />
      </a>
    );

    Markdown to JSX is doing the heavy lifting of rendering my markdown annotations to html. I've also plugged in a few custom overrides to make use of Next features, such as the NextLink to handle routing through the app, as well as an img override to open in a new tab by default.

    Adding In Highlight.js

    Highlight.js is a flexible library that can do exactly what I'm looking for, both on the client and server.

    Since I'm building static pages, I'll reach for their server implementation to call:

    html = hljs.highlightAuto('<h1>Hello World!</h1>').value

    I could use their client side approach, wrapped up in a useEffect. However, that adds to the js bundle sent down the wire. Not to mention, I'd get this ugly flicker effect once the styles kicked in.

    So, I'm opting to build another override.

    Markdown renders code in a <pre> and nested <code> tag. So I'll add my own components to plugin the synchronous syntax highlighting:

    First, importing highlight.js and adding my override:

    import hljs from 'highlight.js';
    
    export default function PostBody({ content }) {
    
      return (
        <div className="markdown">
          <Markdown
            options={{
              overrides: {
                a: NextLink,
                img: BlogImage,
                pre: Pre,
              },
            }}
          >
            {content}
          </Markdown>
        </div>
      );
    }

    And then writing my custom components:

    const CodeBlock = ({className, children}) => {
      children = hljs.highlightAuto(children, ['java', 'javascript', 'python', 'react', 'yaml']).value;
      return (
        <pre>
          <code dangerouslySetInnerHTML={{__html: children}} />
        </pre>
      );
    }
    
    const Pre = ({children, ...rest}) => {  
      return <pre {...rest}>{children}</pre>;
    }

    Violà! The colors you see above are thanks to these changes!

    New Album — Dog Angst 🐶

    Woof

    Lucy's been listening to my teenage emo CDs! Now she's all moody.

    Purchase on 🤘 Bandcamp and Listen on 🙉 Spotify or any of your favorite streaming services!

    Faber – The Medieval Piper

    Listen on Youtube

    Been enjoying sightreading short and sweet 5-finger pieces like this.

    Desk Dino

    🦖

    A study of my destop companion 🦖