Overview
This template is best used for static sites such as documentation and portfolio showcase that can be benefited by using Markdown.
The stack is comprised of Vue.js and Nuxt.js as the core technology for building the template, Nuxt Content for content management and supplemented by Tailwind CSS as the styling library.
Installation
To get started, clone the project template from GitHub.
git clone https://github.com/data-miner00/nuxt-content-template.git
Next, install the dependencies with Pnpm.
pnpm i
If you want to install with other package managers like Npm or Yarn, feel free to delete the pnpm-lock.yaml
and proceed with the package manager of your choice.
After the installation is completed, start the development server by running the dev
command.
pnpm dev
Pre-writing
Before writing any articles in the .md
file, it is advised to add the frontmatter code that describes the article so that it can be used when laying out the individual page. The frontmatter example can be found at /templates/frontmatter.yml
file. It is essentially an assortment of custom properties that relates to the article.
title: Title of the Articledescription: The subtitle describing the title in more details, should be written in sentence-casetopic: Topiccategory: Categoryauthors: - name: Contributor 1 avatar: contrib_1.png - name: Contributor 2 avatar: contrib_2.pngtags: - tutorial - guide - cheatsheetupdatedAt: 2022-11-18T11:37:49.432ZcreatedAt: 2022-11-18T11:37:49.432Z
The recommended properties are listed as follows:
title
: The title (h1) of the article/topic.description
: A longer definition that describes the intention and objective of the article.category
: The main topic of the article.tags
: A list of tags that are related to the article.createdAt
: The timestamp of article creation.updatedAt
: The timestamp of article modification.
However, feel free to add in more custom fields that makes most sense to you.
To access the fields, they can be obtained from the useAsyncData
composables as follow.
<script setup lang="ts">const { data } = await useAsyncData(`content-${path}`, () => { return queryContent(path).findOne();});</script><template> <h1>{{ data?.title }}</h1></template>
The example above demonstrates the access of the custom title
attribute from the frontmatter of the article. Other defined values can be retrieved similarly.
Writing Content
In Nuxt, every .vue
file inside the /pages
folder maps directly to the path of the file name from root accordingly. For instance, the pages/home.vue
maps to /home
in the application.
With Nuxt Content, it is possible to map .md
file within the /content
folder directly to root as well. This will require a [...slug].vue
file to be placed within the /pages
folder in order to work.
If there are conflicting names between the .md
file and the .vue
file in both /content
and /pages
folder, the .vue
file in the /pages
folder will get the precedence and annulling the declaration of the .md
file.
For the record, this page (/guide
) is written in .md
within the /content
folder that is then rendered with predefined stylings and layout.
Table of Content
By default, Nuxt content renders <h2>
and <h3>
only in the ToC and will skip any <h1>
that is present to the markdown because <h1>
is recognized as the main title of the article or page. Any subsequent headings in the article will have to start from <h2>
semantically. Hence, it is recommended to use headings <h2>
and above when writing.
This template only renders out the <h2>
tags in the table of content. To visualize this, consider the following example of heading structure within an article.
├─ Heading 1
│ ├─ Subheading A
│ ├─ Subheading B
│ └─ Subheading C
├─ Heading 2
│ ├─ Subheading A
│ ├─ Subheading B
│ └─ Subheading C
├─ Heading 3
└─ Heading 4
In the ToC, the contents generated will be as follows.
├─ Heading 1
├─ Heading 2
├─ Heading 3
└─ Heading 4
To customize this behaviour to include the subheading as well, head over to /pages/[...slug].vue
and uncomment the codes that will generate the subheading.
Ordering Content
The default ordering is by alphabetical order. To customize the orderings, prepend the filename with numbers followed by an immediate .
such as 1.Introduction.md
and increment the count for subsequent files.
content/
1.frameworks/
1.vue.md
2.nuxt.md
2.examples/
1.vercel.md
2.netlify.md
3.heroku.md
index.md
Images
This is how a potrait image looks like within the prose. It is left aligned and will extend to the max width available in the prose. Images that will be served alongside with the app can be placed within the public
directory. For instance, images within the /public/images
folder can be accessed via the path /images/img.jpg
directly.
![my cool image](/images/demo.png)
The landscape image will most probably took over the full width of the container if they have a wide enough resolution.
For images that are located in /assets/images
folder, they will need to be processed by the build tools by referencing them from source code by using require
or any form of import before they will be included in the final build output.
<template> <img :src="require('~/assets/images/img.jpg')" /></template>
LaTeX Support
This template also comes with the support for
\begin{equation} i \hbar \frac{\partial}{\partial t} \Psi \big(\textbf{r}, t) = \left[- \frac{\hbar^2}{2m}\nabla^2 + V(\textbf{r})\right]\Psi(\textbf{r}, t)\end{equation}
The
Here is another example of matrix rendered with
\begin{pmatrix*}[r] -1 & 2 & 3 \\ 4 & -5 & 6 \\ 7 & 8 & -9\end{pmatrix*}
Styling
This template opens up a lot of room for customization on top of what's currently provided by Nuxt, Nuxt Content, TailwindCSS and some of my touches to make it great.
Content
The content of the article was styled using Tailwind's Typography plugin (@tailwindcss/typography
) that offers a set of pre-defined styles that is enough the make the article sleak and appealing to read through. The style can be customized on the <article>
tag in /pages/[...slug].vue
by using the prose
keyword.
To style an <h2>
inside the article block, prefix the style with prose-h2:
in the article block where prose
is defined in the class.
<article class="prose prose-stone prose-h2:text-blue-400" />
Besides, to modify how the Markdown is translated to Vue components for rendering, create the specific Prose elements within the /components/content
folder. Nuxt will automatically use those elements to render out the Markdown content instead. The list of available overrides includes ProseCode
, ProseH1
, ProseA
etc. The full list can be inspected in the official GitHub repo.
For your reference, examples of the overridden Prose element in this template are ProseCode
, ProseH2
and ProseH3
that can be found in the /components/content
folder.
Custom Components
Nuxt Content allows the creation of custom components that can be embedded to the Markdown script and render it as HTML altogether. There are a couple of syntax that can be used to feature custom components in the Markdown. The first way to do so is by using the MDC syntax.
For inline components, it can be used by prepending a colon in front of the component's name. This will render the component that takes in no props nor children into the page.
:my-component
For block components, it can be used by prefixing the component's name with a double colon, followed by another closing double colon to signify the end of the component. Block component is the component that can accept Markdown content or another component as it's slot content.
::card
Hello world
::
Nesting is supported for the block component as such.
::hero
:::card
A nested card
::card
A super nested card
::
:::
::
To render for a custom named slot inside the component, use the #slot-name
pattern to outline which content to be rendered within which slot.
::card
The slot default text
#description
This will be rendered within the `description` slot in the component.
::
For a custom component that accepts props, simply enclose the desired key-value pairs within a pair of curly braces immediately after the component's name.
::alert{type="warning" color="default"}
The **alert** component
::
Another way of passing props to a custom component is by using the YAML method that is demonstrated as below.
::alert
---
type: warning
color: default
---
The **alert** component
::
Here is a small example on using the custom component with the MDC syntax. The custom component named Card.vue
is used for the following demo.
::card{title="Awesome title!" footer="This is an inconspicuous footer"}
This is a sample paragraph that is **passed** into the custom card's **default slot** for rendering.
::
The code snippet above will have it's content rendered as below.
This is a sample paragraph that is passed into the custom card's default slot for rendering.
Dark Theme
This template uses Tailwind's class-based Dark Mode for theming. A ready to use theme switching component is already provided. It uses the Nuxt Color Mode's useColorMode composable to take care of the theme switching and persisting the theme preference through the browser's Local Storage API. It is incredibly convenient.
const colorMode = useColorMode();colorMode.preference = "dark";colorMode.preference = "light";colorMode.preference = "system";
Code Blocks
The style of the code blocks can be modified to suits your liking by heading over to the content
section in the nuxt.config.ts
configuration file.
export default defineNuxtConfig({ content: { documentDriven: true, highlight: { theme: { default: "github-light", dark: "github-dark", }, preload: ["cpp", "csharp", "rust", "wenyan"], }, },});
In the highlight
section, you can choose the theme that will render out the code blocks for both light and dark mode. Nuxt Content uses Shiki as their code highlighter and it comes along with a wide array of popular themes ready to be used.
The syntax highlighting support are only available for a limited set of languages by default such as HTML, JavaScript, TypeScript and Vue. To enable highlighting for the language of choice, just add in the language identifier into the preload
array.
Tailwind in Markdown
Since Tailwind has been configured to watch for styles in .md
files in the tailwind.config.js
, it can be used freely anywhere in the file. For example, if you want to style a particular word with a text-pink-400
Tailwind class, just wrap it inside a HTML span tag and assign the class name to it.
## My Superfluous TitleLorem <span class="text-pink-400">ipsum</span> dolor sit amet, adispicing elit.
Another way to style an inline text is by using the syntax as shown below. It is simpler and neat than the previous example.
Lorem [ipsum]{.text-pink-400} dolor sit amet, adispicing elit.
Internationalization
To be added.