{"id":18591560,"url":"https://github.com/schnerring/hugo-theme-gruvbox","last_synced_at":"2025-04-10T15:31:40.312Z","repository":{"id":40046748,"uuid":"375866848","full_name":"schnerring/hugo-theme-gruvbox","owner":"schnerring","description":"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.","archived":false,"fork":false,"pushed_at":"2025-04-10T12:36:03.000Z","size":14524,"stargazers_count":224,"open_issues_count":39,"forks_count":55,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-04-10T13:54:51.462Z","etag":null,"topics":["dark-mode","flexsearch","gruvbox","hugo","hugo-theme","jsonresume","theme"],"latest_commit_sha":null,"homepage":"","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/schnerring.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-06-11T00:56:19.000Z","updated_at":"2025-04-09T16:52:50.000Z","dependencies_parsed_at":"2023-12-24T05:51:59.908Z","dependency_job_id":"a59a4087-e7b1-4a31-88f5-f88edce0136a","html_url":"https://github.com/schnerring/hugo-theme-gruvbox","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/schnerring%2Fhugo-theme-gruvbox","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/schnerring%2Fhugo-theme-gruvbox/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/schnerring%2Fhugo-theme-gruvbox/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/schnerring%2Fhugo-theme-gruvbox/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/schnerring","download_url":"https://codeload.github.com/schnerring/hugo-theme-gruvbox/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248243453,"owners_count":21071054,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dark-mode","flexsearch","gruvbox","hugo","hugo-theme","jsonresume","theme"],"created_at":"2024-11-07T01:02:08.892Z","updated_at":"2025-04-10T15:31:39.518Z","avatar_url":"https://github.com/schnerring.png","language":"HTML","funding_links":[],"categories":["HTML"],"sub_categories":[],"readme":"# Gruvbox Hugo Theme\n\nA retro-looking [Hugo](https://gohugo.io/) theme inspired by\n[gruvbox](https://github.com/morhetz/gruvbox) to build secure, fast, and\nSEO-ready websites.\n\nThis theme is easily customizable with features that any coder loves.\n\nI took a lot of inspiration from the\n[Hello Friend](https://github.com/panr/hugo-theme-hello-friend) and\n[Doks](https://github.com/h-enk/doks) Hugo themes.\n\n## DEMO [https://hugo-theme-gruvbox.schnerring.net/](https://hugo-theme-gruvbox.schnerring.net/)\n\n![Screenshot of the theme in dark and light colors](https://raw.githubusercontent.com/schnerring/hugo-theme-gruvbox/main/images/tn.png)\n\n## DISCLAIMER: Project Status\n\nThis theme is still in early development.\n[Check out the issues](https://github.com/schnerring/hugo-theme-gruvbox/issues)\nto see what's still missing.\n\n## Highlights\n\n- [Code highlighting with Prism](#prism)\n- Full-text search with [Flex Search](https://github.com/nextapps-de/flexsearch)\n- Display your CV using structured [JSON Resume](https://jsonresume.org/) data\n- [Integrated image optimization with next-gen image formats and lazy loading](#image-optimization)\n- Dark mode that also changes Prism themes\n- [Dynamic color choices from the Gruvbox color palette](#colors)\n- [Extensible to make it suit your needs](#extensibility)\n- Responsive, mobile-first design\n- Beautiful SVG icons with [Tabler Icons](https://tabler-icons.io/)\n\nA big thank you to the authors of the software that make this theme possible! ❤️\n\n## Quickstart\n\nThe theme requires _extended_ Hugo because it uses Sass/SCSS. You'll also have\nto install Go because the theme uses Go modules.\n\n1. `git clone` the repository and `cd` into it\n2. Run `npm ci` to install the dependencies\n3. Run `hugo server`\n\n## Install The Theme\n\nCreate a new Hugo website:\n\n```shell\nhugo new site example.com\ncd example.com/\n```\n\nInitialize the site as Hugo module\n\n```shell\nhugo mod init example.com\n```\n\nAdd the following to the `hugo.toml` file:\n\n```toml\n[markup]\n  # (Optional) To be able to use all Prism plugins, the theme enables unsafe\n  # rendering by default\n  #_merge = \"deep\"\n\n[build]\n  # Merge build config of the theme\n  _merge = \"deep\"\n\n# This hopefully will be simpler in the future.\n# See: https://github.com/schnerring/hugo-theme-gruvbox/issues/16\n[module]\n  [[module.imports]]\n    path = \"github.com/schnerring/hugo-theme-gruvbox\"\n  [[module.imports]]\n    path = \"github.com/schnerring/hugo-mod-json-resume\"\n    [[module.imports.mounts]]\n      # This will add the sample Richard Hendricks CV data\n      source = \"data\"\n      target = \"data\"\n    [[module.imports.mounts]]\n      source = \"layouts\"\n      target = \"layouts\"\n    [[module.imports.mounts]]\n      source = \"assets/css/json-resume.css\"\n      target = \"assets/css/critical/44-json-resume.css\"\n  [[module.mounts]]\n    # required by hugo-mod-json-resume\n    source = \"node_modules/simple-icons/icons\"\n    target = \"assets/simple-icons\"\n  [[module.mounts]]\n    source = \"assets\"\n    target = \"assets\"\n  [[module.mounts]]\n    source = \"layouts\"\n    target = \"layouts\"\n  [[module.mounts]]\n    source = \"static\"\n    target = \"static\"\n  [[module.mounts]]\n    source = \"node_modules/prismjs\"\n    target = \"assets/prismjs\"\n  [[module.mounts]]\n    source = \"node_modules/prism-themes/themes\"\n    target = \"assets/prism-themes\"\n  [[module.mounts]]\n    source = \"node_modules/typeface-fira-code/files\"\n    target = \"static/fonts\"\n  [[module.mounts]]\n    source = \"node_modules/typeface-roboto-slab/files\"\n    target = \"static/fonts\"\n  [[module.mounts]]\n    source = \"node_modules/@tabler/icons/icons\"\n    target = \"assets/tabler-icons\"\n  [[module.mounts]]\n    # Add hugo_stats.json to Hugo's server watcher\n    source = \"hugo_stats.json\"\n    target = \"assets/watching/hugo_stats.json\"\n```\n\nInstall the theme:\n\n```shell\nhugo mod get\n```\n\nInitialize the NPM `package.json` and install the dependencies:\n\n```shell\nhugo mod npm pack\nnpm install\n```\n\nRun Hugo:\n\n```shell\nhugo server\n```\n\n## Update The Theme\n\nUpdate the Hugo modules:\n\n```shell\nhugo mod get -u\nhugo mod tidy\n```\n\nUpdate the NPM dependencies:\n\n```shell\nhugo mod npm pack\nnpm install\n```\n\n## Colors\n\nTwo options are available to configure the theme colors:\n\n- `defaultTheme`: `dark` or `light` (defaults to `light`)  \n  Default theme color for when a user visits the site for the first time. OS or\n  user preference override this setting.\n  [See this comment for more details.](https://github.com/schnerring/hugo-theme-gruvbox/issues/34#issuecomment-1235870375)\n- `themeColor`: `gray`, `red`, `green`, `yellow`, `blue`, `purple`, `aqua`, or\n  `orange` (defaults to `blue`)  \n  Theme color for things such as links, headings etc.\n- `themeContrast`: `soft`, `medium`, or `hard` (defaults to `medium`)  \n  Theme background color\n\n## Prism\n\nThe theme allows customization of [Prism](https://prismjs.com/) via `hugo.toml`\nparameters:\n\n```toml\n[params]\n  [params.prism]\n    languages = [\n      \"markup\",\n      \"css\",\n      \"clike\",\n      \"javascript\"\n    ]\n    plugins = [\n      \"normalize-whitespace\",\n      \"toolbar\",\n      \"copy-to-clipboard\"\n    ]\n```\n\nIn my opinion, this is the coolest feature of the theme. Other Hugo themes\nusually include a pre-configured version of Prism, which complicates updates and\nchange tracking, and clutters the theme's code base with third-party JavaScript.\n\nThe Prism theme is not configurable because of the integration with the dark\nmode functionality. Toggling between color modes swaps the Prism theme between\n[`gruvbox-dark`](https://github.com/PrismJS/prism-themes/blob/master/themes/prism-gruvbox-dark.css)\nand\n[`gruvbox-light`](https://github.com/PrismJS/prism-themes/blob/master/themes/prism-gruvbox-light.css)\nfrom [github.com/PrismJS/prism-themes](https://github.com/PrismJS/prism-themes).\n\nCheck out the\n[Prism showcase on the Demo site for examples](https://hugo-theme-gruvbox.schnerring.net/blog/prism-code-highlighting-showcase/)\n\n### Explore Prism Features\n\nAfter running `npm install`, explore Prism features like this:\n\n```shell\n# Languages\nls node_modules/prismjs/components\n\n# Plugins\nls node_modules/prismjs/plugins\n```\n\n## Image Optimization\n\nImages are optimized by default without requiring\n[shortcodes](https://gohugo.io/content-management/shortcodes/). A\n[custom render hook](https://gohugo.io/getting-started/configuration-markup#markdown-render-hooks)\ndoes all the heavy lifting (see\n[render-image.html](./layouts/_default/_markup/render-image.html)).\n\nBy default, the theme creates resized versions of images ranging from 300 to 700\npixels wide in increments of 100 pixels.\n\nIf the image format is not [WebP](https://en.wikipedia.org/wiki/WebP), the image\nis converted. The original file format will serve as a fallback for browsers\nthat don't support the WebP format.\n\nNote that only images that are part of the\n[page bundle](https://gohugo.io/content-management/page-bundles/) are processed.\nIf served from the `static/` directory or external sources, the image will be\ndisplayed but not be processed.\n\nAdditionally, all images are lazily loaded to save the bandwidth of your users.\n\n### Configuration\n\nThe default quality is 75%. See the\n[official Image Processing Config Hugo docs](https://gohugo.io/content-management/image-processing/#image-processing-config).\nChange it by adding the following to the `hugo.toml` file:\n\n```toml\n[imaging]\n  quality = 75\n```\n\nChange the resize behavior:\n\n```toml\n[params]\n  [params.imageResize]\n    min = 300\n    max = 700\n    increment = 100\n```\n\n### Captions\n\n```markdown\n![Alt text](image-url.jpg \"Caption with **markdown support**\")\n```\n\n[The demo site features examples you can look at](https://hugo-theme-gruvbox.schnerring.net/blog/image-optimization/).\nI also use the theme for [my website](https://schnerring.net).\n\n### Blog Post Covers\n\nAdd blog post covers by defining them in the\n[front matter](https://gohugo.io/content-management/front-matter/) of your\nposts:\n\n```markdown\n---\ncover:\n  src: my-blog-cover.jpg\n  alt: A beautiful image containing interesting things\n  caption: [Source](https://www.flickr.com/)\n---\n```\n\n## Embed Video Files\n\nUse the\n[video shortcode](https://github.com/schnerring/hugo-theme-gruvbox/blob/main/layouts/shortcodes/video.html)\nto embed your video files from\n[Page Resources](https://gohugo.io/content-management/page-resources/).\n\nWith a page bundle looking like the following:\n\n```text\nembed-videos/\n|-- index.md\n|-- my-video.jpg\n|-- my-video.mp4\n|-- my-video.webm\n```\n\nYou can embed `my-video` like this:\n\n```markdown\n{{\u003c video src=\"my-video\" autoplay=\"true\" controls=\"false\" loop=\"true\" \u003e}}\n```\n\nThe shortcode looks for media files matching the filename `my-video*`. For each\n`video` MIME type file, a `\u003csource\u003e` element is added. The first `image` MIME\ntype file is used as `poster` (thumbnail). It will render the following HTML:\n\n```html\n\u003cvideo\n  autoplay\n  loop\n  poster=\"/blog/embed-videos/my-video.jpg\"\n  width=\"100%\"\n  playsinline\n\u003e\n  \u003csource src=\"/blog/embed-videos/my-video.mp4\" type=\"video/mp4\" /\u003e\n  \u003csource src=\"/blog/embed-videos/my-video.webm\" type=\"video/webm\" /\u003e\n\u003c/video\u003e\n```\n\nYou can set a Markdown `caption`, wrapping the `\u003cvideo\u003e` inside a `\u003cfigure`\u003e.\n\nAdditionally, the shortcode allows you to set the following attributes:\n\n| Attribute   | Default |\n| ----------- | ------- |\n| autoplay    | `false` |\n| controls    | `true`  |\n| height      |         |\n| loop        | `false` |\n| muted       | `true`  |\n| preload     |         |\n| width       | `100%`  |\n| playsinline | `true`  |\n\n[Learn more about the `\u003cvideo\u003e` attributes here.](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video#attributes)\n\n## SEO\n\nDue to the\n[European Copyright Directive](https://wayback.archive-it.org/12090/20210304045117/https://ec.europa.eu/digital-single-market/en/modernisation-eu-copyright-rules)\nit is required to opt into displaying\n[snippets](https://developers.google.com/search/docs/advanced/appearance/title-link?hl=en)\nin search engine results.\n\nBy default, every page (except 404) includes the\n`index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1`\nrobots meta value, opting into all snippet features.\n\nYou can override the robots meta value in the front matter of your pages:\n\n```markdown\n---\nrobots: noindex, nofollow\n---\n```\n\n## Social Share Links\n\nConfigure social share links in the Hugo config like this:\n\n```toml\n[params]\n  [[params.socialShare]]\n    iconSuite = \"simple-icon\"\n    iconName = \"facebook\"\n    formatString = \"https://www.facebook.com/sharer.php?u={url}\"\n  [[params.socialShare]]\n    iconSuite = \"simple-icon\"\n    iconName = \"reddit\"\n    formatString = \"https://reddit.com/submit?url={url}\u0026title={title}\"\n  [[params.socialShare]]\n    iconSuite = \"tabler-icon\"\n    iconName = \"outline/mail\"\n    formatString = \"mailto:?subject={title}\u0026body={url}\"\n```\n\nUse the `iconSuite` setting to specify the icon suite used for the social share\nlink: `simple-icon` or `tabler-icon`. Select an icon from the suite with the\n`iconName` setting. Tabler icons come in two distinct styles, `filled` and\n`outline`. You'll have to the prefix the `iconName` accordingly, e.g.\n`iconName = \"outline/sun\"`.\n\nThe `formatString` supports the following placeholders:\n\n- `{url}` is replaced with the `.Permalink` of the post\n- `{title}` is replaced with the `.Title` of the post\n\nTo enable social share links, set the following in the post's front matter:\n\n```markdown\n---\nsocialShare: true\n---\n```\n\nCheck out the\n[Social Share URLs repo on GitHub](https://github.com/bradvin/social-share-urls)\nfor more format strings.\n\n## Favicon\n\nThe favicons and [corresponding markup](./layouts/partials/head/favicons.html)\nwere generated with the free\n[RealFaviconGenerator.net](https://realfavicongenerator.net/).\n\nThe easiest way to replace the default favicons is to generate them using\nRealFaviconGenerator.net and put the generated files into the `static/`\ndirectory.\n\n## Extensibility\n\nYou can extend the theme by overriding the following partials in the\n`layouts/partials` directory which by default are empty placeholder files:\n\n- [`head/head_start.html`](./layouts/partials/head_start.html)  \n  Custom HTML at the start of `\u003chead\u003e`\n- [`head/head_end.html`](./layouts/partials/head_end.html)  \n  Custom HTML at the end of `\u003chead\u003e`\n- [`footer_end.html`](./layouts/partials/footer_end.html)  \n  Custom HTML at the end of `\u003cbody\u003e`\n- [`comments.html`](./layouts/partials/comments.html)  \n  Comments at the end of posts\n\n### Example: Adding KaTeX Support to the Theme\n\n[KaTeX](https://katex.org/) is a fast, easy-to-use JavaScript library for TeX\nmath rendering on the web. Let's add it to the theme via `npm`. First, add the\nfollowing to the `package.hugo.json` file:\n\n```json\n\"dependencies\": {\n  \"katex\": \"^0.16.8\"\n}\n```\n\nThen run `hugo mod npm pack` to sync the `package.hugo.json` dependencies with\n`package.json`. Run `npm install` after. We then need to mount the\n`node_modules/katex` folder into Hugo's virtual filesystem by adding the\nfollowing to the `config/_default/module.toml` file:\n\n```toml\n[[mounts]]\n  source = \"node_modules/katex\"\n  target = \"assets/katex\"\n```\n\nWe can then add the following to `layouts/partials/head/head_end.html`:\n\n\u003c!-- prettier-ignore-start --\u003e\n\n```html\n{{ if .Params.katex }}\n  {{ $katexCSS := resources.Get \"katex/dist/katex.min.css\" }}\n  \u003clink\n    rel=\"stylesheet\"\n    href=\"{{ $katexCSS }}\"\n    {{ if hugo.IsProduction }}\n      integrity=\"{{ $katexCSS.Data.Integrity }}\"\n    {{ end }}\n    crossorigin=\"anonymous\"\n  /\u003e\n\n  {{ $katexJS := resources.Get \"katex/dist/katex.min.js\" }}\n  \u003cscript\n    defer\n    src=\"{{ $katexJS.RelPermalink }}\"\n    {{ if hugo.IsProduction }}\n      integrity=\"{{ $katexJS.Data.Integrity }}\"\n    {{ end }}\n    crossorigin=\"anonymous\"\n  \u003e\u003c/script\u003e\n\n  {{ $autoRender := resources.Get \"katex/dist/contrib/auto-render.min.js\" }}\n  \u003cscript\n    defer\n    src=\"{{ $autoRender.RelPermalink }}\"\n    {{ if hugo.IsProduction }}\n      integrity=\"{{ $autoRender.Data.Integrity }}\"\n    {{ end }}\n    crossorigin=\"anonymous\"\n    onload=\"renderMathInElement(document.body);\"\n  \u003e\u003c/script\u003e\n{{ end }}\n```\n\n\u003c!-- prettier-ignore-end --\u003e\n\nThe only thing left is enabling KaTeX in the front matter of our content:\n\n```markdown\n---\ntitle: \"Hello World\"\ndescription: \"The first post of this blog\"\ndate: 2021-03-14T15:00:21+01:00\ndraft: false\nkatex: true\n---\n\nI'm a .NET developer by trade, so let's say hello in C#!\n```\n\n## Configure the Tag Cloud\n\nThe theme comes with a tag cloud partial. It is included in the sidebar, but it\nis disabled by default. If you wish to configure it, add the following to the\n`[params]` section in the `hugo.toml` file:\n\n```toml\n[params.tagCloud]\n  enable = true\n  minFontSizeRem = 0.8\n  maxFontSizeRem = 2.0\n```\n\n## Remove the Sidebar\n\nIf you want to get rid of the sidebar, add an empty `data/json_resume/en.json`\nfile with the following content:\n\n```json\n{\n  \"$schema\": \"https://raw.githubusercontent.com/jsonresume/resume-schema/v1.0.0/schema.json\",\n  \"basics\": {},\n  \"work\": [],\n  \"volunteer\": [],\n  \"education\": [],\n  \"awards\": [],\n  \"certificates\": [],\n  \"publications\": [],\n  \"skills\": [],\n  \"languages\": [],\n  \"interests\": [],\n  \"references\": [],\n  \"projects\": [],\n  \"meta\": {\n    \"canonical\": \"https://raw.githubusercontent.com/jsonresume/resume-schema/master/resume.json\",\n    \"version\": \"v1.0.0\",\n    \"lastModified\": \"2017-12-24T15:53:00\"\n  }\n}\n```\n\n## Extend CSS\n\nThe theme uses PostCSS with following plugins:\n\n- [postcss-import](https://github.com/postcss/postcss-import)\n- [postcss-url](https://github.com/postcss/postcss-url)\n- [postcss-nesting](https://github.com/csstools/postcss-plugins/tree/main/plugins/postcss-nesting)\n- [postcss-custom-media](https://github.com/postcss/postcss-custom-media)\n\nAdditionally the following plugins are used if building the site with\n`hugo -e production`:\n\n- [postcss-preset-env](https://github.com/csstools/postcss-plugins/tree/main/plugin-packs/postcss-preset-env)\n- [cssnano](https://github.com/cssnano/cssnano) for minification\n- [@fullhuman/postcss-purgecss](https://github.com/FullHuman/purgecss)\n\nInside the `assets/css` two folders exist, `critical` and `non-critical`. Files\ninside `critical` are concatenated during build time and inlined into the\n`\u003chead\u003e` element. The styles target mostly\n[above the fold content](https://en.wikipedia.org/wiki/Above_the_fold#In_web_design).\nTry to keep inline CSS to a minimum because it can't be cached and will be\ninlined into every single page. Files inside `non-critical` are concatenated\ninto a single file and included as `\u003cstyle\u003e`. Most of the styles are in there.\n\nFiles are concatenated in lexicographic order of their file names. File names\nstart with two digits and a hyphen: `NN-`. The order of files might differ\nbetween Linux and Windows, so using this convention improves cross-platform\ncompatibility.\n[You might know this approach if you're familiar with Xorg](https://wiki.archlinux.org/title/Xorg#Using_.conf_files).\n\nYou can add new CSS files to the PostCSS pipeline like this:\n\n- `critical/50-foo.css`\n- `non-critical/05-bar.css`\n- `non-critical/99-last.css`\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fschnerring%2Fhugo-theme-gruvbox","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fschnerring%2Fhugo-theme-gruvbox","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fschnerring%2Fhugo-theme-gruvbox/lists"}