Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/schnerring/hugo-theme-gruvbox

A retro-looking Hugo theme inspired by gruvbox. The pastel colors are high contrast, easily distinguishable, pleasing to the eye, and feature light and dark color palettes.
https://github.com/schnerring/hugo-theme-gruvbox

dark-mode flexsearch gruvbox hugo hugo-theme jsonresume theme

Last synced: 3 months ago
JSON representation

A retro-looking Hugo theme inspired by gruvbox. The pastel colors are high contrast, easily distinguishable, pleasing to the eye, and feature light and dark color palettes.

Awesome Lists containing this project

README

        

# Gruvbox Hugo Theme

A retro-looking [Hugo](https://gohugo.io/) theme inspired by
[gruvbox](https://github.com/morhetz/gruvbox) to build secure, fast, and
SEO-ready websites.

This theme is easily customizable with features that any coder loves.

I took a lot of inspiration from the
[Hello Friend](https://github.com/panr/hugo-theme-hello-friend) and
[Doks](https://github.com/h-enk/doks) Hugo themes.

## DEMO [https://hugo-theme-gruvbox.schnerring.net/](https://hugo-theme-gruvbox.schnerring.net/)

![Screenshot of the theme in dark and light colors](https://raw.githubusercontent.com/schnerring/hugo-theme-gruvbox/main/images/tn.png)

## DISCLAIMER: Project Status

This theme is still in early development.
[Check out the issues](https://github.com/schnerring/hugo-theme-gruvbox/issues)
to see what's still missing.

## Highlights

- [Code highlighting with Prism](#prism)
- Full-text search with [Flex Search](https://github.com/nextapps-de/flexsearch)
- Display your CV using structured [JSON Resume](https://jsonresume.org/) data
- [Integrated image optimization with next-gen image formats and lazy loading](#image-optimization)
- Dark mode that also changes Prism themes
- [Dynamic color choices from the Gruvbox color palette](#colors)
- [Extensible to make it suit your needs](#extensibility)
- Responsive, mobile-first design
- Beautiful SVG icons with [Tabler Icons](https://tabler-icons.io/)

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

## Quickstart

The theme requires _extended_ Hugo because it uses Sass/SCSS. You'll also have
to install Go because the theme uses Go modules.

1. `git clone` the repository and `cd` into it
2. Run `npm ci` to install the dependencies
3. Run `hugo server`

## Install The Theme

Create a new Hugo website:

```shell
hugo new site example.com
cd example.com/
```

Initialize the site as Hugo module

```shell
hugo mod init example.com
```

Add the following to the `hugo.toml` file:

```toml
[markup]
# (Optional) To be able to use all Prism plugins, the theme enables unsafe
# rendering by default
#_merge = "deep"

[build]
# Merge build config of the theme
_merge = "deep"

# This hopefully will be simpler in the future.
# See: https://github.com/schnerring/hugo-theme-gruvbox/issues/16
[module]
[[module.imports]]
path = "github.com/schnerring/hugo-theme-gruvbox"
[[module.imports]]
path = "github.com/schnerring/hugo-mod-json-resume"
[[module.imports.mounts]]
# This will add the sample Richard Hendricks CV data
source = "data"
target = "data"
[[module.imports.mounts]]
source = "layouts"
target = "layouts"
[[module.imports.mounts]]
source = "assets/css/json-resume.css"
target = "assets/css/critical/44-json-resume.css"
[[module.mounts]]
# required by hugo-mod-json-resume
source = "node_modules/simple-icons/icons"
target = "assets/simple-icons"
[[module.mounts]]
source = "assets"
target = "assets"
[[module.mounts]]
source = "layouts"
target = "layouts"
[[module.mounts]]
source = "static"
target = "static"
[[module.mounts]]
source = "node_modules/prismjs"
target = "assets/prismjs"
[[module.mounts]]
source = "node_modules/prism-themes/themes"
target = "assets/prism-themes"
[[module.mounts]]
source = "node_modules/typeface-fira-code/files"
target = "static/fonts"
[[module.mounts]]
source = "node_modules/typeface-roboto-slab/files"
target = "static/fonts"
[[module.mounts]]
source = "node_modules/@tabler/icons/icons"
target = "assets/tabler-icons"
[[module.mounts]]
# Add hugo_stats.json to Hugo's server watcher
source = "hugo_stats.json"
target = "assets/watching/hugo_stats.json"
```

Install the theme:

```shell
hugo mod get
```

Initialize the NPM `package.json` and install the dependencies:

```shell
hugo mod npm pack
npm install
```

Run Hugo:

```shell
hugo server
```

## Update The Theme

Update the Hugo modules:

```shell
hugo mod get -u
hugo mod tidy
```

Update the NPM dependencies:

```shell
hugo mod npm pack
npm install
```

## Colors

Two options are available to configure the theme colors:

- `defaultTheme`: `dark` or `light` (defaults to `light`)
Default theme color for when a user visits the site for the first time. OS or
user preference override this setting.
[See this comment for more details.](https://github.com/schnerring/hugo-theme-gruvbox/issues/34#issuecomment-1235870375)
- `themeColor`: `gray`, `red`, `green`, `yellow`, `blue`, `purple`, `aqua`, or
`orange` (defaults to `blue`)
Theme color for things such as links, headings etc.
- `themeContrast`: `soft`, `medium`, or `hard` (defaults to `medium`)
Theme background color

## Prism

The theme allows customization of [Prism](https://prismjs.com/) via `hugo.toml`
parameters:

```toml
[params]
[params.prism]
languages = [
"markup",
"css",
"clike",
"javascript"
]
plugins = [
"normalize-whitespace",
"toolbar",
"copy-to-clipboard"
]
```

In my opinion, this is the coolest feature of the theme. Other Hugo themes
usually include a pre-configured version of Prism, which complicates updates and
change tracking, and clutters the theme's code base with third-party JavaScript.

The Prism theme is not configurable because of the integration with the dark
mode functionality. Toggling between color modes swaps the Prism theme between
[`gruvbox-dark`](https://github.com/PrismJS/prism-themes/blob/master/themes/prism-gruvbox-dark.css)
and
[`gruvbox-light`](https://github.com/PrismJS/prism-themes/blob/master/themes/prism-gruvbox-light.css)
from [github.com/PrismJS/prism-themes](https://github.com/PrismJS/prism-themes).

Check out the
[Prism showcase on the Demo site for examples](https://hugo-theme-gruvbox.schnerring.net/blog/prism-code-highlighting-showcase/)

### Explore Prism Features

After running `npm install`, explore Prism features like this:

```shell
# Languages
ls node_modules/prismjs/components

# Plugins
ls node_modules/prismjs/plugins
```

## Image Optimization

Images are optimized by default without requiring
[shortcodes](https://gohugo.io/content-management/shortcodes/). A
[custom render hook](https://gohugo.io/getting-started/configuration-markup#markdown-render-hooks)
does all the heavy lifting (see
[render-image.html](./layouts/_default/_markup/render-image.html)).

By default, the theme creates resized versions of images ranging from 300 to 700
pixels wide in increments of 100 pixels.

If the image format is not [WebP](https://en.wikipedia.org/wiki/WebP), the image
is converted. The original file format will serve as a fallback for browsers
that don't support the WebP format.

Note that only images that are part of the
[page bundle](https://gohugo.io/content-management/page-bundles/) are processed.
If served from the `static/` directory or external sources, the image will be
displayed but not be processed.

Additionally, all images are lazily loaded to save the bandwidth of your users.

### Configuration

The default quality is 75%. See the
[official Image Processing Config Hugo docs](https://gohugo.io/content-management/image-processing/#image-processing-config).
Change it by adding the following to the `hugo.toml` file:

```toml
[imaging]
quality = 75
```

Change the resize behavior:

```toml
[params]
[params.imageResize]
min = 300
max = 700
increment = 100
```

### Captions

```markdown
![Alt text](image-url.jpg "Caption with **markdown support**")
```

[The demo site features examples you can look at](https://hugo-theme-gruvbox.schnerring.net/blog/image-optimization/).
I also use the theme for [my website](https://schnerring.net).

### Blog Post Covers

Add blog post covers by defining them in the
[front matter](https://gohugo.io/content-management/front-matter/) of your
posts:

```markdown
---
cover:
src: my-blog-cover.jpg
alt: A beautiful image containing interesting things
caption: [Source](https://www.flickr.com/)
---
```

## Embed Video Files

Use the
[video shortcode](https://github.com/schnerring/hugo-theme-gruvbox/blob/main/layouts/shortcodes/video.html)
to embed your video files from
[Page Resources](https://gohugo.io/content-management/page-resources/).

With a page bundle looking like the following:

```text
embed-videos/
|-- index.md
|-- my-video.jpg
|-- my-video.mp4
|-- my-video.webm
```

You can embed `my-video` like this:

```markdown
{{< video src="my-video" autoplay="true" controls="false" loop="true" >}}
```

The shortcode looks for media files matching the filename `my-video*`. For each
`video` MIME type file, a `` element is added. The first `image` MIME
type file is used as `poster` (thumbnail). It will render the following HTML:

```html


```

You can set a Markdown `caption`, wrapping the `` inside a `.

Additionally, the shortcode allows you to set the following attributes:

| Attribute | Default |
| ----------- | ------- |
| autoplay | `false` |
| controls | `true` |
| height | |
| loop | `false` |
| muted | `true` |
| preload | |
| width | `100%` |
| playsinline | `true` |

[Learn more about the `` attributes here.](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video#attributes)

## SEO

Due to the
[European Copyright Directive](https://wayback.archive-it.org/12090/20210304045117/https://ec.europa.eu/digital-single-market/en/modernisation-eu-copyright-rules)
it is required to opt into displaying
[snippets](https://developers.google.com/search/docs/advanced/appearance/title-link?hl=en)
in search engine results.

By default, every page (except 404) includes the
`index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1`
robots meta value, opting into all snippet features.

You can override the robots meta value in the front matter of your pages:

```markdown
---
robots: noindex, nofollow
---
```

## Social Share Links

Configure social share links in the Hugo config like this:

```toml
[params]
[[params.socialShare]]
iconSuite = "simple-icon"
iconName = "facebook"
formatString = "https://www.facebook.com/sharer.php?u={url}"
[[params.socialShare]]
iconSuite = "simple-icon"
iconName = "reddit"
formatString = "https://reddit.com/submit?url={url}&title={title}"
[[params.socialShare]]
iconSuite = "tabler-icon"
iconName = "outline/mail"
formatString = "mailto:?subject={title}&body={url}"
```

Use the `iconSuite` setting to specify the icon suite used for the social share
link: `simple-icon` or `tabler-icon`. Select an icon from the suite with the
`iconName` setting. Tabler icons come in two distinct styles, `filled` and
`outline`. You'll have to the prefix the `iconName` accordingly, e.g.
`iconName = "outline/sun"`.

The `formatString` supports the following placeholders:

- `{url}` is replaced with the `.Permalink` of the post
- `{title}` is replaced with the `.Title` of the post

To enable social share links, set the following in the post's front matter:

```markdown
---
socialShare: true
---
```

Check out the
[Social Share URLs repo on GitHub](https://github.com/bradvin/social-share-urls)
for more format strings.

## Favicon

The favicons and [corresponding markup](./layouts/partials/head/favicons.html)
were generated with the free
[RealFaviconGenerator.net](https://realfavicongenerator.net/).

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_end.html`](./layouts/partials/head_end.html)
Custom HTML at the end of ``
- [`footer_end.html`](./layouts/partials/footer_end.html)
Custom HTML at the end of ``
- [`comments.html`](./layouts/partials/comments.html)
Comments at the end of posts

### Example: Adding KaTeX Support to the Theme

[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:

```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:

```toml
[[mounts]]
source = "node_modules/katex"
target = "assets/katex"
```

We can then add the following to `layouts/partials/head/head_end.html`:

```html
{{ if .Params.katex }}
{{ $katexCSS := resources.Get "katex/dist/katex.min.css" }}

{{ $katexJS := resources.Get "katex/dist/katex.min.js" }}

{{ $autoRender := resources.Get "katex/dist/contrib/auto-render.min.js" }}

{{ end }}
```

The only thing left is enabling KaTeX in the front matter of our content:

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

I'm a .NET developer by trade, so let's say hello in C#!
```

## Configure the Tag Cloud

The theme comes with a tag cloud partial. It is included in the sidebar, but it
is disabled by default. If you wish to configure it, add the following to the
`[params]` section in the `hugo.toml` file:

```toml
[params.tagCloud]
enable = true
minFontSizeRem = 0.8
maxFontSizeRem = 2.0
```

## Remove the Sidebar

If you want to get rid of the sidebar, add an empty `data/json_resume/en.json`
file with the following content:

```json
{
"$schema": "https://raw.githubusercontent.com/jsonresume/resume-schema/v1.0.0/schema.json",
"basics": {},
"work": [],
"volunteer": [],
"education": [],
"awards": [],
"certificates": [],
"publications": [],
"skills": [],
"languages": [],
"interests": [],
"references": [],
"projects": [],
"meta": {
"canonical": "https://raw.githubusercontent.com/jsonresume/resume-schema/master/resume.json",
"version": "v1.0.0",
"lastModified": "2017-12-24T15:53:00"
}
}
```

## Extend CSS

The theme uses PostCSS with following plugins:

- [postcss-import](https://github.com/postcss/postcss-import)
- [postcss-url](https://github.com/postcss/postcss-url)
- [postcss-nesting](https://github.com/csstools/postcss-plugins/tree/main/plugins/postcss-nesting)
- [postcss-custom-media](https://github.com/postcss/postcss-custom-media)

Additionally the following plugins are used if building the site with
`hugo -e production`:

- [postcss-preset-env](https://github.com/csstools/postcss-plugins/tree/main/plugin-packs/postcss-preset-env)
- [cssnano](https://github.com/cssnano/cssnano) for minification
- [@fullhuman/postcss-purgecss](https://github.com/FullHuman/purgecss)

Inside the `assets/css` two folders exist, `critical` and `non-critical`. Files
inside `critical` are concatenated during build time and inlined into the
`` element. The styles target mostly
[above the fold content](https://en.wikipedia.org/wiki/Above_the_fold#In_web_design).
Try to keep inline CSS to a minimum because it can't be cached and will be
inlined into every single page. Files inside `non-critical` are concatenated
into a single file and included as ``. Most of the styles are in there.

Files are concatenated in lexicographic order of their file names. File names
start with two digits and a hyphen: `NN-`. The order of files might differ
between Linux and Windows, so using this convention improves cross-platform
compatibility.
[You might know this approach if you're familiar with Xorg](https://wiki.archlinux.org/title/Xorg#Using_.conf_files).

You can add new CSS files to the PostCSS pipeline like this:

- `critical/50-foo.css`
- `non-critical/05-bar.css`
- `non-critical/99-last.css`