Published on

UA SDS Blog Development & Maintenance

Authors

WARNING

This post is under development, so there may be errors or some sections may be unclear. Please let me know if you spot anything or have any questions/comments/concerns!

Now that you're up and running...

Welcome to your blog site!

If you're just starting, it probably looks fairly tacky. Thankfully it doesn't take too much effort to start making it your own.

This post will outline the elements of your site development and maintenance that you will care most about, how to do some customization, and generally what you will most often be tweaking to maintain.

If you have just gotten everything up and running, your VSCode environment should look something like this:

new project

How do I customize my site?

A quick explainer can be found here at @timlrx Tailwind Blog template README

Also worth a read

This post goes into more detailed customization, and some items that are unique to this template.

Site Metadata

The first step in customizing your site is to personalize its metadata. In your Explorer window, navigate to the data folder and open siteMetadata.js.

site metadata

Update your properties as you would like. Below is reference for the mapping of each property to the site.

site metadata

You can comment out any links that you don't want (6).

Use the stickynav logical property to set whether you would like your navbar to stick to the top while scrolling.

For analytics, newsletter, and comments, please see this @timrlx post.

Pictures and Icons

There are several files that comprise all of the logos and icons that you will care about for your site. We will reference this figure below.

site logos and avatar

(1) To update your avatar photo sitewide, which is used primarily for your Author image and for the splash page hero, replace the avatar.png file in the public/static folder.

(2) The favicons require update if you want something other than the Block A logo. Unfortunately, I don't have a simple set of instructions here to update these without downloading the Adobe tools. Fortunately, if you are a student, you can get them for free here:

Adobe Creative Cloud

I have made an Adobe Illustator template, which can be found in the public/static/favicons/template directory, called icons.ai. It has premade canvases that can be used to export and overwrite each of the files in the favicons folder. Be sure to export the correct file type and the correct corresponding dimensions for each.

(3) public/static/images/logo.png is only used in the Hero, but it's also useful to have a logo file that can be used throughout the site. It's also used in the siteMetadata.js as a site logo parameter, although I am not clear how it is used in the web app.

(4) In the data folder, logo.svg should be changed to your logo if you would like something other than the Block A, but it must be an SVG file. The template in public/static/favicons/template also has a canvas to export your own logo as an SVG. This logo will be on your navbar, and can be used anywhere else on your side by the same method used in components/Header.tsx.

Colors

Site Colors

The site's color schemes are dictated by CSS (namely in css/tailwind.css), however the primary hooks for changing colors across the board can be found in the tailwind.config.js file in the root directory. You will primarily want to edit the colors property in the module_exports (should be lines 27-30).

colors: {
        primary: colors.rose,
        gray: colors.slate,
      },

primary will primarily affect text, links, etc. gray will affect dark mode colors including the background. You can use the color palettes defined by Tailwind CSS to make quick "broad strokes" updates:

Tailwind Color Palettes

Of course, all of the CSS is customizable, so any fields in tailwind.config.js as well as css/tailwind.css can be modified to change the overall looks of the site.

Code Chunk Colors

The css/prism.css CSS file is dedicated to the styling of code chunks. There are great themes available at this repo if you want to try something different than the template:

PrismJS Prism Themes

Fonts

There are two steps to modifying the default font for the site.

The first step requires opening app/layout.tsx. For reference, we can look at how to import the default font Space_Grotesk.

import { Space_Grotesk } from 'next/font/google'
// ...
const space_grotesk = Space_Grotesk({
  subsets: ['latin'],
  display: 'swap',
  variable: '--font-space-grotesk',
})

We can choose a font we want from next/font/google, see the below documentation.

Once we create a variable for our chosen font, the default font for the site can be modified using the fontFamily property in tailwind.config.js.

      fontFamily: {
        sans: ['var(--font-space-grotesk)', ...fontFamily.sans],
      },

Blog Posts, Authors, and CV

Blog Posts

All of the mdx files in your data/blog folder will render to your site automatically. Any posts that you don't want on your site should be removed or moved to the data/archive/blog folder.

blogs

To make a new post, create a new mdx file in data/blog. You will need to add the header fields in order for everything to render. Use the other posts in the folder as reference, or check out the example for how to format a blog post header here:

@timrlx Post Formatting

Blog posts are markdown, and very similar to other kinds of markdown that you have seen. You can even use LaTeX\LaTeX to render equations. I recommend opening the data/blog/deriving-ols-estimator.mdx post to see examples of how the LaTeX\LaTeX syntax works in posts.

Additionally, the Next.js framework allows us to incorporate components in your blog posts by passing component objects to be available in blogs via the components/MDXComponents.tsx. There are a wealth of great components out there that can make your blogs more animated, reactive, and interactive. See this part of the post for more on this.

If you want to take a look at some examples, feel free to check out any posts on my live page.

Alex's Blog Posts

Authors

Be sure to update the data/authors/default.mdx page with all of your information. This will update your About page, so make sure to hit all of the high-level points and contact information about you (you can also have a look at mine for ideas).

CV

You can customize your CV by modifying the data/resume/default.mdx file, using the template as guidance for formatting (it's just pretty simple markdown syntax). Keep in mind that the header levels correspond to indents in a table-of-contents style sidebar on the CV page.

Deploying Git Repositories with Vercel

IMPORTANT

UPDATE AS OF DECEMBER 2024: Vercel now uses Node.js version 22.X as its default for new projects when running yarn build, meaning that the first time you deploy it will fail! This is fine, let it fail! Once the build has failed, navigate to the Project page on Vercel and click on the Settings tab (above your project's name). Scroll down to "Node.js Version" and from the pulldown menu select 20.X (the default will have 22.X). Click the Save button below, then go back to the Project tab. Click Redeploy, don't modify any options on the pop up and redeploy the page. This time it should build successfully. See this link if you get stuck: https://vercel.com/docs/functions/runtimes/node-js/node-js-versions

Time to start deploying!

More Advanced Stuff

WARNING

This is where it gets a little heavy

MDXComponents

Here is the tutorial that comes from the original blog template by @timrlx.

How can I add a custom MDX component?

Here's an example on how to create a donut chart from Chart.js (assuming you already have the dependencies installed) and use it in MDX posts. First, create a new DonutChart.tsx component in components:

'use client'

import { Doughnut } from 'react-chartjs-2'
import { Chart as ChartJS, ArcElement, Tooltip, Legend } from 'chart.js'

ChartJS.register(ArcElement, Tooltip, Legend)

const DonutChart = ({ data }) => {
  return <Doughnut data={data} />
}

export default Doughnut

Since the underlying Doughnut component uses React hooks, we add the 'use client' directive to specify that it is a client side component. Also, there is an existing issue which prevents named components from being used, so we need to export the component as the default export.

Next, add the component to MDXComponents.tsx:

...
+ import DonutChart from './DonutChart'

export const components: MDXComponents = {
  Image,
  TOCInline,
  a: CustomLink,
  pre: Pre,
+  DonutChart,
  BlogNewsletterForm,
}

You can now use the component in .mdx files:

## Example Donut Chart

export const data = {
  labels: ['Red', 'Blue', 'Yellow'],
  datasets: [
    {
      label: '# of Votes',
      data: [12, 19, 3],
      backgroundColor: [
        'rgba(255, 99, 132, 0.2)',
        'rgba(54, 162, 235, 0.2)',
        'rgba(255, 206, 86, 0.2)',
      ],
      borderColor: ['rgba(255, 99, 132, 1)', 'rgba(54, 162, 235, 1)', 'rgba(255, 206, 86, 1)'],
      borderWidth: 1,
    },
  ],
}

<DonutChart data={data} />

Layouts, Components, and Pages

If you take a look at the blog template from which this was originally created...

Tailwind CSS Blog

...you'll notice a difference in the layout of the landing page.

Each page is rendered from Typescript files in the app folder, namely app/layout.tsx which controls the overall layout of the whole site, and in the case of the landing page, app/Main.tsx.

If we open app/Main.tsx we can see where I manually placed a 'Component', the SDSHero.

// ...
// import custom SDSHero (sds_custom)
import SDSHero from '@/components/SDSHero'
// ...
export default function Home({ posts }) {
  return (
    <>
      <SDSHero />
// ...

The SDSHero Component is a very simple custom component that I created for the site, and I suggest you open it and have a quick look. Next.js is an object-oriented framework, and Components are objects that are importable throughout layouts in the web app that get rendered dynamically using contentlayer.

If we, for example, want to remove the SDSHero from the landing page, we can just comment out or delete it from app/Main.tsx.

When we want to make a new page for our site (maybe something different than a blog, or an about me page), it needs to be defined in the app folder with a subdirectory that contains a page.tsx file, which defines all of the imports, layouts of all the components, just overall what the page should look like. It also needs to be instructed to be rendered with contentlayer. We make the structure of the new page we want in our web app in the app folder, and then we must modify contentlayer.config.ts in the root folder. We may also need some css and components to help make it render the way we want.

Resume Example

The app/resume layout was a custom layout that I added to this site (credit to Trillium's Blog for the code), and we can run through how it was created. First, we will create a new directory in our app folder. Here, we use app/resume. Inside this folder we will make a page.tsx. This page is what ultimately get rendered when we navigate to {blogurl}/resume.

In this case, the page.tsx that I copied from Trillium's Blog uses some dependencies that will also need to be accounted for.

  • We need a Resume Layout, which is a layout that can be found at layouts/ResumeLayout.tsx. This was something that I added manually, and you may need to create your own layout if you are making a new page.
  • The ResumeLayout needs a custom component import { ToC } from '@/components/ToC'. This was also something I added manually, and you may need to import components into your layouts.

NOTE

Always check the imports of any new components, layouts, or any other pages that you decide to add if you are importing from externally (maybe you found something cool online). If you don't recognize an import, or you are getting errors when you render, you will need to install the dependency into your environment. You can stop the dev server and install from your terminal using yarn add {package} or npm install {package} (documentation online will usually give you something you can copy/paste). Most packages can be found on https://www.npmjs.com/. Also note, when you install new packages to your project, the package.json updates automatically, so that dependency will now be automatically attached to your environment for this project.

  • Lastly, we need to create a new directory, data/resume and add default.mdx. This will be the content that we fill out for the resume layout object that gets rendered on the app page.

Once these files are added in their appropriate folders, we need to pass the structure into contentlayer so that it will be dynamically rendered.

Inside of contentlayer.config.ts in the root, we need to add a new export so that contentlayer will export our resume to be rendered by the app. Notice the filePathPattern property where we define the path to the mdx content that will be rendered and define the fields that can be defined in the header and passed into the layout.

//need to add Resume contentlayer configuration, any new react app page needs added here, use others for format (sds_custom)
export const Resume = defineDocumentType(() => ({
  name: 'Resume',
  filePathPattern: 'resume/**/*.mdx',
  contentType: 'mdx',
  fields: {
    name: { type: 'string', required: true },
    avatar: { type: 'string' },
    occupation: { type: 'string' },
    company: { type: 'string' },
    email: { type: 'string' },
    linkedin: { type: 'string' },
    github: { type: 'string' },
    layout: { type: 'string' },
  },
  computedFields,
}))

Almost there. Our last step is to add the Resume export we just created to the contentlayer documentTypes so that contentlayer knows to generate it.

// documentTypes: Resume must be manually added for document type export for react app page to build (sds_custom)
export default makeSource({
  contentDirPath: 'data',
  documentTypes: [Blog, Authors, Resume],

And we're done! Now, when we navigate to {blogurl}/resume, we will render our new page!

Also, you might notice on the nav bar it's called CV, and on the layout document it says "Cirriculum Vitae". You can of course modify this, but I chose CV since that matches the communications requirement. An exercise you may try: how do I produce this Resume page at {blogurl}/cv?

NOTE

I will be adding to this page periodically, and I am happy to add any material by request!

Other Resources