mirror of
https://github.com/davegallant/davegallant.github.io.git
synced 2025-08-07 00:58:13 +00:00
Rename theme path
This commit is contained in:
573
themes/hugo-theme-gruvbox/README.md
Normal file
573
themes/hugo-theme-gruvbox/README.md
Normal file
@@ -0,0 +1,573 @@
|
||||
# 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/)
|
||||
|
||||

|
||||
|
||||
## 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 `config.toml` file:
|
||||
|
||||
```toml
|
||||
[markup]
|
||||
# (Optional) To be able to use all Prism plugins, the theme enables unsafe
|
||||
# rendering by default
|
||||
#_merge = "deep"
|
||||
|
||||
[build]
|
||||
# The theme enables writeStats which is required for PurgeCSS
|
||||
_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]]
|
||||
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]]
|
||||
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"
|
||||
```
|
||||
|
||||
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
|
||||
`config.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 `config.toml` file:
|
||||
|
||||
```toml
|
||||
[imaging]
|
||||
quality = 75
|
||||
```
|
||||
|
||||
Change the resize behavior:
|
||||
|
||||
```toml
|
||||
[params]
|
||||
[params.imageResize]
|
||||
min = 300
|
||||
max = 700
|
||||
increment = 100
|
||||
```
|
||||
|
||||
### Captions
|
||||
|
||||
```markdown
|
||||

|
||||
```
|
||||
|
||||
[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 `<source>` element is added. The first `image` MIME
|
||||
type file is used as `poster` (thumbnail). It will render the following HTML:
|
||||
|
||||
```html
|
||||
<video
|
||||
autoplay
|
||||
loop
|
||||
poster="/blog/embed-videos/my-video.jpg"
|
||||
width="100%"
|
||||
playsinline
|
||||
>
|
||||
<source src="/blog/embed-videos/my-video.mp4" type="video/mp4" />
|
||||
<source src="/blog/embed-videos/my-video.webm" type="video/webm" />
|
||||
</video>
|
||||
```
|
||||
|
||||
You can set a Markdown `caption`, wrapping the `<video>` inside a `<figure`>.
|
||||
|
||||
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 `<video>` 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 = "mail"
|
||||
formatString = "mailto:?subject={title}&body={url}"
|
||||
```
|
||||
|
||||
Use the `iconSuite` option 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` option.
|
||||
|
||||
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/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
|
||||
|
||||
### 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`:
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
```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 }}
|
||||
```
|
||||
|
||||
<!-- prettier-ignore-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 `config.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/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
|
||||
`<head>` 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 `<style>`. 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`
|
Reference in New Issue
Block a user