Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Server side rendering of math equations #350

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 35 additions & 78 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ to see what's still missing.
- [Extensible to make it suit your needs](#extensibility)
- Responsive, mobile-first design
- Beautiful SVG icons with [Tabler Icons](https://tabler-icons.io/)
- [Math typesetting](#math-typesetting) via Hugo's [embedded KaTeX engine](https://gohugo.io/functions/transform/tomath/)

A big thank you to the authors of the software that make this theme possible! ❤️

Expand Down Expand Up @@ -414,97 +415,53 @@ The easiest way to replace the default favicons is to generate them using
RealFaviconGenerator.net and put the generated files into the `static/`
directory.

## Extensibility

You can extend the theme by overriding the following partials in the
`layouts/partials` directory which by default are empty placeholder files:

- [`head/head_start.html`](./layouts/partials/head_start.html)
Custom HTML at the start of `<head>`
- [`head/head_end.html`](./layouts/partials/head_end.html)
Custom HTML at the end of `<head>`
- [`footer_end.html`](./layouts/partials/footer_end.html)
Custom HTML at the end of `<body>`
- [`comments.html`](./layouts/partials/comments.html)
Comments at the end of posts
## Math Typesetting

### Example: Adding KaTeX Support to the Theme
For math typesetting in a Hugo project, you can leverage hugo's internal
[KaTeX](https://katex.org/) rendering engine.

[KaTeX](https://katex.org/) is a fast, easy-to-use JavaScript library for TeX
math rendering on the web. Let's add it to the theme via `npm`. First, add the
following to the `package.hugo.json` file:
If you want to use mathematical or chemical equations in site, enable the
[Goldmark passthrough extension](https://gohugo.io/render-hooks/passthrough/)
and define delimiters for block and inline formulae in your config file:

```json
"dependencies": {
"katex": "^0.16.8"
}
```

Then run `hugo mod npm pack` to sync the `package.hugo.json` dependencies with
`package.json`. Run `npm install` after. We then need to mount the
`node_modules/katex` folder into Hugo's virtual filesystem by adding the
following to the `config/_default/module.toml` file:
**`hugo.toml`**

```toml
[[mounts]]
source = "node_modules/katex"
target = "assets/katex"
[markup]
[markup.goldmark]
[markup.goldmark.extensions]
[markup.goldmark.extensions.passthrough]
enable = true
[markup.goldmark.extensions.passthrough.delimiters]
block = [['\[', '\]'], ['$$', '$$']]
inline = [['\(', '\)']]
```

We can then add the following to `layouts/partials/head/head_end.html`:
Afterwards you can author formulae using the standard $\LaTeX$ syntax:

<!-- prettier-ignore-start -->
### Examples

```html
{{ if .Params.katex }}
{{ $katexCSS := resources.Get "katex/dist/katex.min.css" }}
<link
rel="stylesheet"
href="{{ $katexCSS }}"
{{ if hugo.IsProduction }}
integrity="{{ $katexCSS.Data.Integrity }}"
{{ end }}
crossorigin="anonymous"
/>

{{ $katexJS := resources.Get "katex/dist/katex.min.js" }}
<script
defer
src="{{ $katexJS.RelPermalink }}"
{{ if hugo.IsProduction }}
integrity="{{ $katexJS.Data.Integrity }}"
{{ end }}
crossorigin="anonymous"
></script>

{{ $autoRender := resources.Get "katex/dist/contrib/auto-render.min.js" }}
<script
defer
src="{{ $autoRender.RelPermalink }}"
{{ if hugo.IsProduction }}
integrity="{{ $autoRender.Data.Integrity }}"
{{ end }}
crossorigin="anonymous"
onload="renderMathInElement(document.body);"
></script>
{{ end }}
```
Inline math: $\varphi = \dfrac{1+\sqrt5}{2}= 1.6180339887… $

<!-- prettier-ignore-end -->
Block math:

The only thing left is enabling KaTeX in the front matter of our content:
$$
\tag*{(1)} \varphi = 1+\frac{1} {1+\frac{1} {1+\frac{1} {1+\cdots} } }
$$

```markdown
---
title: "Hello World"
description: "The first post of this blog"
date: 2021-03-14T15:00:21+01:00
draft: false
katex: true
---
## Extensibility

I'm a .NET developer by trade, so let's say hello in C#!
```
You can extend the theme by overriding the following partials in the
`layouts/partials` directory which by default are empty placeholder files:

- [`head/head_start.html`](./layouts/partials/head_start.html)
Custom HTML at the start of `<head>`
- [`head/head_end.html`](./layouts/partials/head_end.html)
Custom HTML at the end of `<head>`
- [`footer_end.html`](./layouts/partials/footer_end.html)
Custom HTML at the end of `<body>`
- [`comments.html`](./layouts/partials/comments.html)
Comments at the end of posts

## Configure the Tag Cloud

Expand Down
10 changes: 9 additions & 1 deletion config/_default/hugo.toml
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
baseURL = "http://localhost"
copyright = "Copyright © 2021"
title = "hugo-theme-gruvbox"
#paginate = 10
enableRobotsTXT = true
# Enable to calculate the last modified date from Git history and show it in the post header
#enableGitInfo = true

[pagination]
#pagerSize = 10

[build]
noJSConfigInAssets = true
[build.buildStats]
Expand All @@ -17,6 +19,12 @@ enableRobotsTXT = true

[markup]
[markup.goldmark]
[markup.goldmark.extensions]
[markup.goldmark.extensions.passthrough]
enable = true
[markup.goldmark.extensions.passthrough.delimiters]
block = [['\[', '\]'], ['$$', '$$']]
inline = [['\(', '\)']]
[markup.goldmark.renderer]
# This setting allows inlining <script> and <style> tags in markdown,
# which is useful and required to use Prism plugins, but may be dangerous
Expand Down
2 changes: 1 addition & 1 deletion config/_default/module.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#replacements = "github.com/schnerring/hugo-mod-json-resume -> ../../hugo-mod-json-resume"
[hugoVersion]
extended = true
min = "0.128.0"
min = "0.141.0"
[[imports]]
path = "github.com/schnerring/hugo-mod-json-resume"
[[imports.mounts]]
Expand Down
56 changes: 26 additions & 30 deletions content/blog/math-typesetting.md
Original file line number Diff line number Diff line change
@@ -1,51 +1,47 @@
---
author: Hugo Authors
title: Math Typesetting
date: 2019-03-08
description: A brief guide to setup KaTeX
date: 2025-02-18
description: A brief guide to setup and use KaTeX
math: true
tags:
- "hugo-basic-example"
---

Mathematical notation in a Hugo project can be enabled by using third party JavaScript libraries.
For math typesetting in a Hugo project, you can leverage hugo's internal [\(\KaTeX\)](https://katex.org/) rendering engine.
<!--more-->

In this example we will be using [KaTeX](https://katex.org/)
If you want to use mathematical or chemical equations in site, enable the [Goldmark passthrough extension](https://gohugo.io/render-hooks/passthrough/) and define delimiters for block and inline formulae in your config file:

- Create a partial under `/layouts/partials/math.html`
- Within this partial reference the [Auto-render Extension](https://katex.org/docs/autorender.html) or host these scripts locally.
- Include the partial in your templates like so:
**`hugo.toml`**

```bash
{{ if or .Params.math .Site.Params.math }}
{{ partial "math.html" . }}
{{ end }}
```toml
[markup]
[markup.goldmark]
[markup.goldmark.extensions]
[markup.goldmark.extensions.passthrough]
enable = true
[markup.goldmark.extensions.passthrough.delimiters]
block = [['\[', '\]'], ['$$', '$$']]
inline = [['\(', '\)']]
```

- To enable KaTex globally set the parameter `math` to `true` in a project's configuration
- To enable KaTex on a per page basis include the parameter `math: true` in content files

**Note:** Use the online reference of [Supported TeX Functions](https://katex.org/docs/supported.html)

{{< math.inline >}}
{{ if or .Page.Params.math .Site.Params.math }}
<!-- KaTeX -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.css" integrity="sha384-zB1R0rpPzHqg7Kpt0Aljp8JPLqbXI3bhnPWROx27a9N0Ll6ZP/+DiW/UqRcLbRjq" crossorigin="anonymous">
<script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.js" integrity="sha384-y23I5Q6l+B6vatafAwxRu/0oK/79VlbSz7Q9aiSZUvyWYIYsd+qj+o24G5ZU2zJz" crossorigin="anonymous"></script>
<script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/contrib/auto-render.min.js" integrity="sha384-kWPLUVMOks5AQFrykwIup5lo0m3iMkkHrD0uJ4H5cjeGihAutqP0yW0J6dpFiVkI" crossorigin="anonymous" onload="renderMathInElement(document.body);"></script>
{{ end }}
{{</ math.inline >}}
Afterwards you can author formulae using the standard \(\LaTeX\) syntax:

### Examples

{{< math.inline >}}
<p>
Inline math: \(\varphi = \dfrac{1+\sqrt5}{2}= 1.6180339887…\)
</p>
{{</ math.inline >}}
Inline math: \(\varphi = \dfrac{1+\sqrt5}{2}= 1.6180339887… \)

Block math:

$$
\varphi = 1+\frac{1} {1+\frac{1} {1+\frac{1} {1+\cdots} } }
\tag*{(1)} \varphi = 1+\frac{1} {1+\frac{1} {1+\frac{1} {1+\cdots} } }
$$

Chemical equations:

\[
\tag*{(2)} \ce{Zn^2+ <=>[+ 2OH-][+ 2H+] $\underset{\text{amphoteric hydroxide}}{\ce{Zn(OH)2 v}}$ <=>[+ 2OH-][+ 2H+] $\underset{\text{tetrahydroxozincate}}{\ce{[Zn(OH)4]^2-}}$}
\]

**Note:** Use the online reference of [Supported TeX Functions](https://katex.org/docs/supported.html)
9 changes: 9 additions & 0 deletions layouts/_default/_markup/render-passthrough.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{{- $opts := dict "output" "htmlAndMathml" "displayMode" (eq .Type "block") }}
{{- with try (transform.ToMath .Inner $opts) }}
{{- with .Err }}
{{ errorf "Unable to render mathematical markup to HTML using the transform.ToMath function. The KaTeX display engine threw the following error: %s: see %s." . $.Position }}
{{- else }}
{{- .Value }}
{{- $.Page.Store.Set "hasMath" true }}
{{- end }}
{{- end -}}
14 changes: 14 additions & 0 deletions layouts/partials/head/head.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,20 @@

{{ partial "head/favicons.html" . }}

{{ $noop := .WordCount }}
{{ if .Page.Store.Get "hasMath" }}
{{ $katex_css_url := printf "https://cdn.jsdelivr.net/npm/katex@latest/dist/katex%s.css" (cond hugo.IsProduction ".min" "") -}}
{{ with try (resources.GetRemote $katex_css_url) -}}
{{ with .Err -}}
{{ errorf "Could not retrieve KaTeX css file from CDN. Reason: %s." . -}}
{{ else with.Value -}}
{{ with resources.Copy (printf "css/katex%s.css" (cond hugo.IsProduction ".min" "")) . }}
{{ $secureCSS := . | resources.Fingerprint "sha512" -}}
<link rel="stylesheet" href="{{- .RelPermalink -}}" integrity="{{- $secureCSS.Data.Integrity -}}" crossorigin="anonymous">
{{ end -}}
{{ end -}}
{{ end -}}
{{ end }}

<!-- Extensibility -->
{{ partial "head/head_end.html" . }}
Expand Down