# 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 `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 ![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 `