Add themes in-tree
8
go.mod
@@ -1,8 +0,0 @@
|
||||
module davegallant.github.io
|
||||
|
||||
go 1.21
|
||||
|
||||
require (
|
||||
github.com/davegallant/hugo-theme-gruvbox v0.0.0-20240106163015-62aac1ea9f6d // indirect
|
||||
github.com/schnerring/hugo-mod-json-resume v0.0.0-20231224014047-e651a547c19a // indirect
|
||||
)
|
6
go.sum
@@ -1,6 +0,0 @@
|
||||
github.com/davegallant/hugo-theme-gruvbox v0.0.0-20240102231105-90b486f98b82 h1:X9jUG5D4OyxLjT3OTsL5TN3jFdpTXyLJJcRpLbgCsSc=
|
||||
github.com/davegallant/hugo-theme-gruvbox v0.0.0-20240102231105-90b486f98b82/go.mod h1:BQehNdf/SB/+bCc031OVsLECIgB9ZaN1dfUFKTeOIuo=
|
||||
github.com/davegallant/hugo-theme-gruvbox v0.0.0-20240106163015-62aac1ea9f6d h1:HCGtUIiR/0t+PnuB/dYhU1ZX9rKNsEnc5EToW6vWLr0=
|
||||
github.com/davegallant/hugo-theme-gruvbox v0.0.0-20240106163015-62aac1ea9f6d/go.mod h1:BQehNdf/SB/+bCc031OVsLECIgB9ZaN1dfUFKTeOIuo=
|
||||
github.com/schnerring/hugo-mod-json-resume v0.0.0-20231224014047-e651a547c19a h1:EZRiOf0iW5k9lycVv3LngzSsGUxDRszYS4U7ea2r8RY=
|
||||
github.com/schnerring/hugo-mod-json-resume v0.0.0-20231224014047-e651a547c19a/go.mod h1:5dixHC0WHu0w2Aqb8hsOCrIU1OBYr1w5Q6HZAmTub7Q=
|
33
package.json
@@ -1,37 +1,4 @@
|
||||
{
|
||||
"comments": {
|
||||
"dependencies": {
|
||||
"@tabler/icons": "github.com/davegallant/hugo-theme-gruvbox",
|
||||
"flexsearch": "github.com/davegallant/hugo-theme-gruvbox",
|
||||
"normalize.css": "github.com/davegallant/hugo-theme-gruvbox",
|
||||
"prism-themes": "github.com/davegallant/hugo-theme-gruvbox",
|
||||
"prismjs": "github.com/davegallant/hugo-theme-gruvbox",
|
||||
"simple-icons": "github.com/schnerring/hugo-mod-json-resume",
|
||||
"typeface-fira-code": "github.com/davegallant/hugo-theme-gruvbox",
|
||||
"typeface-roboto-slab": "github.com/davegallant/hugo-theme-gruvbox"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@fullhuman/postcss-purgecss": "github.com/davegallant/hugo-theme-gruvbox",
|
||||
"cssnano": "github.com/davegallant/hugo-theme-gruvbox",
|
||||
"eslint": "github.com/davegallant/hugo-theme-gruvbox",
|
||||
"eslint-config-prettier": "github.com/davegallant/hugo-theme-gruvbox",
|
||||
"eslint-plugin-prettier": "github.com/davegallant/hugo-theme-gruvbox",
|
||||
"husky": "github.com/davegallant/hugo-theme-gruvbox",
|
||||
"lint-staged": "github.com/davegallant/hugo-theme-gruvbox",
|
||||
"markdownlint-cli": "github.com/davegallant/hugo-theme-gruvbox",
|
||||
"postcss": "github.com/davegallant/hugo-theme-gruvbox",
|
||||
"postcss-cli": "github.com/davegallant/hugo-theme-gruvbox",
|
||||
"postcss-custom-media": "github.com/davegallant/hugo-theme-gruvbox",
|
||||
"postcss-import": "github.com/davegallant/hugo-theme-gruvbox",
|
||||
"postcss-nesting": "github.com/davegallant/hugo-theme-gruvbox",
|
||||
"postcss-preset-env": "github.com/davegallant/hugo-theme-gruvbox",
|
||||
"postcss-url": "github.com/davegallant/hugo-theme-gruvbox",
|
||||
"prettier": "github.com/davegallant/hugo-theme-gruvbox",
|
||||
"prettier-plugin-go-template": "github.com/davegallant/hugo-theme-gruvbox",
|
||||
"stylelint": "github.com/davegallant/hugo-theme-gruvbox",
|
||||
"stylelint-prettier": "github.com/davegallant/hugo-theme-gruvbox"
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@tabler/icons": "^2.44.0",
|
||||
"flexsearch": "^0.7.31",
|
||||
|
@@ -0,0 +1,7 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 2
|
||||
indent_style = space
|
@@ -0,0 +1,5 @@
|
||||
assets/js/flexsearch.js
|
||||
assets/js/prism.js
|
||||
|
||||
public
|
||||
resources
|
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es6": true,
|
||||
"node": true
|
||||
},
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:prettier/recommended"
|
||||
],
|
||||
"parserOptions": {
|
||||
"sourceType": "module"
|
||||
}
|
||||
}
|
43
themes/github.com/davegallant/hugo-theme-gruvbox/.github/renovate.json
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": ["config:base"],
|
||||
"rebaseWhen": "behind-base-branch",
|
||||
"npm": {
|
||||
"fileMatch": ["(^|/)package\\.hugo\\.json$"],
|
||||
"rangeStrategy": "bump",
|
||||
"updateLockFiles": false,
|
||||
"ignoreTests": true,
|
||||
"ignorePaths": [
|
||||
"package.json",
|
||||
|
||||
"**/node_modules/**",
|
||||
"**/bower_components/**",
|
||||
"**/vendor/**",
|
||||
"**/examples/**",
|
||||
"**/__tests__/**",
|
||||
"**/test/**",
|
||||
"**/tests/**",
|
||||
"**/__fixtures__/**"
|
||||
]
|
||||
},
|
||||
"gomod": {
|
||||
"fileMatch": ["(^|/)go\\.mod$"],
|
||||
"rangeStrategy": "bump"
|
||||
},
|
||||
"packageRules": [
|
||||
{
|
||||
"matchManagers": ["gomod"],
|
||||
"matchDepTypes": ["indirect"],
|
||||
"enabled": true,
|
||||
"groupName": "Hugo Modules"
|
||||
},
|
||||
{
|
||||
"extends": "packages:linters",
|
||||
"groupName": "linters"
|
||||
},
|
||||
{
|
||||
"extends": "packages:postcss",
|
||||
"groupName": "postcss packages"
|
||||
}
|
||||
]
|
||||
}
|
84
themes/github.com/davegallant/hugo-theme-gruvbox/.github/workflows/publish.yml
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
name: Publish Hugo Site
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
update_hugo_npm_dependencies:
|
||||
name: Update Hugo npm Dependencies
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
outputs:
|
||||
commit_hash: ${{ steps.commit_changes.outputs.commit_hash }}
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "18"
|
||||
|
||||
- name: Install Hugo
|
||||
uses: peaceiris/actions-hugo@v2
|
||||
with:
|
||||
hugo-version: "0.111.3"
|
||||
extended: true
|
||||
|
||||
- name: Write composite package.json
|
||||
run: hugo mod npm pack
|
||||
|
||||
- name: Install npm Packages
|
||||
run: npm install
|
||||
|
||||
- name: Display Changes
|
||||
run: git status
|
||||
|
||||
- name: Commit Changes
|
||||
id: commit_changes
|
||||
uses: stefanzweifel/git-auto-commit-action@v5
|
||||
with:
|
||||
commit_message: Update Hugo npm Dependencies
|
||||
|
||||
publish:
|
||||
name: Publish Hugo Site
|
||||
needs: update_hugo_npm_dependencies
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
deployments: write
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0 # Fetch all history for .GitInfo and .Lastmod
|
||||
ref: ${{ needs.update_hugo_npm_dependencies.outputs.commit_hash }}
|
||||
|
||||
- name: Install Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "18"
|
||||
|
||||
- name: Install Hugo
|
||||
uses: peaceiris/actions-hugo@v2
|
||||
with:
|
||||
hugo-version: "0.111.3"
|
||||
extended: true
|
||||
|
||||
- name: Install npm Packages
|
||||
run: npm ci
|
||||
|
||||
- name: Build Hugo
|
||||
run: hugo --minify
|
||||
|
||||
- name: Deploy to Cloudflare Pages
|
||||
uses: cloudflare/pages-action@v1
|
||||
with:
|
||||
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||
projectName: hugo-theme-gruvbox
|
||||
directory: ./public
|
||||
gitHubToken: ${{ secrets.GITHUB_TOKEN }}
|
35
themes/github.com/davegallant/hugo-theme-gruvbox/.github/workflows/renovate-hugo-modules.yml
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
name: Renovate Hugo Modules
|
||||
|
||||
on: pull_request
|
||||
|
||||
jobs:
|
||||
renovate_hugo_modules:
|
||||
name: Renovate Hugo Modules
|
||||
if: startsWith(github.head_ref, 'renovate/hugo-modules')
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Pull Request HEAD Commit
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
|
||||
- name: Install Hugo
|
||||
uses: peaceiris/actions-hugo@v2
|
||||
with:
|
||||
hugo-version: "0.111.3"
|
||||
extended: true
|
||||
|
||||
- name: Update All Hugo Modules
|
||||
run: hugo mod get -u
|
||||
|
||||
- name: Tidy Hugo Modules
|
||||
run: hugo mod tidy
|
||||
|
||||
- name: Display Changes
|
||||
run: git status
|
||||
|
||||
- name: Commit Changes
|
||||
uses: stefanzweifel/git-auto-commit-action@v5
|
||||
with:
|
||||
commit_message: Renovate Hugo Modules
|
||||
commit_author: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
|
159
themes/github.com/davegallant/hugo-theme-gruvbox/.gitignore
vendored
Normal file
@@ -0,0 +1,159 @@
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/hugo,node
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=hugo,node
|
||||
|
||||
### Hugo ###
|
||||
# Generated files by hugo
|
||||
/public/
|
||||
/resources/_gen/
|
||||
/assets/jsconfig.json
|
||||
hugo_stats.json
|
||||
|
||||
# Executable may be added to repository
|
||||
hugo.exe
|
||||
hugo.darwin
|
||||
hugo.linux
|
||||
|
||||
# Temporary lock file while building
|
||||
/.hugo_build.lock
|
||||
|
||||
### Node ###
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Snowpack dependency directory (https://snowpack.dev/)
|
||||
web_modules/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional stylelint cache
|
||||
.stylelintcache
|
||||
|
||||
# Microbundle cache
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variable files
|
||||
.env
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.env.local
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
.parcel-cache
|
||||
|
||||
# Next.js build output
|
||||
.next
|
||||
out
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
.nuxt
|
||||
dist
|
||||
|
||||
# Gatsby files
|
||||
.cache/
|
||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# vuepress v2.x temp and cache directory
|
||||
.temp
|
||||
|
||||
# Docusaurus cache and generated files
|
||||
.docusaurus
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
.tern-port
|
||||
|
||||
# Stores VSCode versions used for testing VSCode extensions
|
||||
.vscode-test
|
||||
|
||||
# yarn v2
|
||||
.yarn/cache
|
||||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.*
|
||||
|
||||
### Node Patch ###
|
||||
# Serverless Webpack directories
|
||||
.webpack/
|
||||
|
||||
# Optional stylelint cache
|
||||
|
||||
# SvelteKit build / generate output
|
||||
.svelte-kit
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/hugo,node
|
1
themes/github.com/davegallant/hugo-theme-gruvbox/.husky/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
_
|
@@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
npx lint-staged
|
@@ -0,0 +1,11 @@
|
||||
node_modules
|
||||
|
||||
public
|
||||
resources
|
||||
|
||||
# Leave content from gohugoio/hugoBasicExample as is
|
||||
content/blog/emoji-support.md
|
||||
content/blog/markdown-syntax.md
|
||||
content/blog/math-typesetting.md
|
||||
content/blog/placeholder-text.md
|
||||
content/blog/rich-content.md
|
@@ -0,0 +1,4 @@
|
||||
assets/css/critical/15-colors.css
|
||||
assets/css/non-critical/00-vendor.css
|
||||
assets/js/flexsearch.js
|
||||
assets/js/prism.js
|
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"plugins": ["prettier-plugin-go-template"],
|
||||
"proseWrap": "always",
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.html"],
|
||||
"options": {
|
||||
"parser": "go-template"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@@ -0,0 +1,5 @@
|
||||
assets/css/critical/15-colors.css
|
||||
assets/css/non-critical/00-vendor.css
|
||||
|
||||
public
|
||||
resources
|
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"extends": ["stylelint-prettier/recommended"]
|
||||
}
|
21
themes/github.com/davegallant/hugo-theme-gruvbox/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 Michael Schnerring
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
577
themes/github.com/davegallant/hugo-theme-gruvbox/README.md
Normal file
@@ -0,0 +1,577 @@
|
||||
# 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]]
|
||||
# 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"
|
||||
```
|
||||
|
||||
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`
|
@@ -0,0 +1,10 @@
|
||||
---
|
||||
title: "{{ humanize .Name | title }}"
|
||||
date: "{{ .Date }}"
|
||||
draft: true
|
||||
comments: false
|
||||
socialShare: true
|
||||
toc: false
|
||||
cover:
|
||||
src: cover.png
|
||||
---
|
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
Critical CSS for above-the-fold content, delivered inline to increase first
|
||||
paint performance
|
||||
*/
|
||||
|
||||
/*! purgecss start ignore */
|
||||
|
||||
/* Typefaces */
|
||||
@import "typeface-roboto-slab";
|
||||
@import "typeface-fira-code";
|
||||
|
||||
/* Normalize */
|
||||
@import "normalize.css/normalize.css";
|
||||
|
||||
/*! purgecss end ignore */
|
||||
|
||||
/*! CC BY-SA 3.0 License | https://stackoverflow.com/a/36118384/1154965 */
|
||||
@keyframes blink {
|
||||
50% {
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Default license header for non-vendor CSS source code that follows */
|
||||
/*! MIT License | github.com/schnerring/hugo-theme-gruvbox */
|
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
Bootstrap 5 breakpoints
|
||||
See: https://getbootstrap.com/docs/5.0/layout/breakpoints/#available-breakpoints
|
||||
*/
|
||||
@custom-media --sm (min-width: 576px);
|
||||
@custom-media --md (min-width: 768px);
|
||||
@custom-media --lg (min-width: 992px);
|
||||
@custom-media --xl (min-width: 1200px);
|
||||
@custom-media --xxl (min-width: 1400px);
|
@@ -0,0 +1,87 @@
|
||||
{{ $themeContrast := .Param "themeContrast" | default "medium" }}
|
||||
{{ $backgroundColor := "bg0" }}
|
||||
{{ if eq $themeContrast "soft" }}
|
||||
{{ $backgroundColor = "bg0_s" }}
|
||||
{{ else if eq $themeContrast "hard" }}
|
||||
{{ $backgroundColor = "bg0_h" }}
|
||||
{{ end }}
|
||||
|
||||
:root[data-theme="light"] {
|
||||
--bg: var(--{{ $backgroundColor }});
|
||||
--bg0: #fbf1c7;
|
||||
--bg0_h: #f9f5d7;
|
||||
--bg0_s: #f2e5bc;
|
||||
--bg1: #ebdbb2;
|
||||
--bg2: #d5c4a1;
|
||||
--bg3: #bdae93;
|
||||
--bg4: #a89984;
|
||||
--fg: var(--fg1);
|
||||
--fg0: #282828;
|
||||
--fg1: #3c3836;
|
||||
--fg2: #504945;
|
||||
--fg3: #665c54;
|
||||
--fg4: #7c6f64;
|
||||
--gray1: var(--fg4);
|
||||
--gray2: #928374;
|
||||
--red1: #cc241d;
|
||||
--red2: #9d0006;
|
||||
--green1: #98971a;
|
||||
--green2: #797403;
|
||||
--yellow1: #d79921;
|
||||
--yellow2: #b57614;
|
||||
--blue1: #458588;
|
||||
--blue2: #076678;
|
||||
--purple1: #b16286;
|
||||
--purple2: #8f3f71;
|
||||
--aqua1: #689d6a;
|
||||
--aqua2: #427b58;
|
||||
--orange1: #d65d0e;
|
||||
--orange2: #af3a03;
|
||||
|
||||
& .light--hidden {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
:root[data-theme="dark"] {
|
||||
--bg: var(--{{ $backgroundColor }});
|
||||
--bg0: #282828;
|
||||
--bg0_h: #1d2021;
|
||||
--bg0_s: #32302f;
|
||||
--bg1: #3c3836;
|
||||
--bg2: #504945;
|
||||
--bg3: #665c54;
|
||||
--bg4: #7c6f64;
|
||||
--fg: var(--fg1);
|
||||
--fg0: #fbf1c7;
|
||||
--fg1: #ebdbb2;
|
||||
--fg2: #d5c4a1;
|
||||
--fg3: #bdae93;
|
||||
--fg4: #a89984;
|
||||
--gray1: var(--fg4);
|
||||
--gray2: #928374;
|
||||
--red1: #cc241d;
|
||||
--red2: #fb4934;
|
||||
--green1: #98971a;
|
||||
--green2: #b8bb26;
|
||||
--yellow1: #d79921;
|
||||
--yellow2: #fabd2f;
|
||||
--blue1: #458588;
|
||||
--blue2: #83a598;
|
||||
--purple1: #b16286;
|
||||
--purple2: #d3869b;
|
||||
--aqua1: #689d6a;
|
||||
--aqua2: #8ec07c;
|
||||
--orange1: #d65d0e;
|
||||
--orange2: #fe8019;
|
||||
|
||||
& .dark--hidden {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
:root {
|
||||
{{ $themeColor := .Param "themeColor" | default "blue" }}
|
||||
--primary: var(--{{ $themeColor }}1);
|
||||
--primary-alt: var(--{{ $themeColor }}2);
|
||||
}
|
@@ -0,0 +1,238 @@
|
||||
:root {
|
||||
--font-monospace: "Fira Code", "Lucida Console", Monaco, monospace;
|
||||
--font-sans-serif: Verdana, Helvetica, sans-serif;
|
||||
--font-serif: "Roboto Slab", Georgia, serif;
|
||||
}
|
||||
|
||||
html {
|
||||
font-family: var(--font-serif);
|
||||
font-size: 1rem;
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
body {
|
||||
background: var(--bg);
|
||||
color: var(--fg);
|
||||
line-height: 1.675;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
strong {
|
||||
letter-spacing: 0.35px;
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a.link--external::after {
|
||||
/* 2009 = Thin Space */
|
||||
content: "\2009↗";
|
||||
}
|
||||
|
||||
img,
|
||||
video {
|
||||
border: 2px solid var(--bg1);
|
||||
height: auto;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
figure {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
figcaption {
|
||||
color: var(--fg3);
|
||||
font-family: var(--font-serif);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
*::selection {
|
||||
color: var(--fg0);
|
||||
background: var(--bg4);
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
color: var(--fg0);
|
||||
font-family: var(--font-monospace);
|
||||
font-weight: 300;
|
||||
line-height: 1.4;
|
||||
|
||||
& code {
|
||||
font-size: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
border-bottom: 1px solid var(--bg1);
|
||||
}
|
||||
|
||||
h1,
|
||||
h2 {
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.875rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.75rem;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.625rem;
|
||||
}
|
||||
|
||||
@media (--md) {
|
||||
h1 {
|
||||
font-size: 2.375rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 1.375rem;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
table {
|
||||
table-layout: fixed;
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
margin: 2rem 0;
|
||||
}
|
||||
|
||||
table,
|
||||
th,
|
||||
td {
|
||||
border: 1px solid var(--bg1);
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: none;
|
||||
background: var(--bg1);
|
||||
height: 1px;
|
||||
margin: 3rem auto;
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
mark {
|
||||
background: var(--yellow1);
|
||||
color: var(--bg0);
|
||||
}
|
||||
|
||||
abbr {
|
||||
text-underline-offset: 0.2rem;
|
||||
}
|
||||
|
||||
blockquote,
|
||||
code,
|
||||
kbd,
|
||||
mark,
|
||||
pre {
|
||||
border-radius: 0.2rem;
|
||||
padding: 0 0.2em;
|
||||
}
|
||||
|
||||
pre code {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
blockquote,
|
||||
code,
|
||||
kbd,
|
||||
pre,
|
||||
th {
|
||||
background: var(--bg1);
|
||||
}
|
||||
|
||||
code,
|
||||
kbd,
|
||||
pre,
|
||||
th {
|
||||
font-family: var(--font-monospace);
|
||||
}
|
||||
|
||||
code,
|
||||
kbd {
|
||||
& code,
|
||||
& kbd {
|
||||
background: var(--bg2);
|
||||
}
|
||||
}
|
||||
|
||||
blockquote,
|
||||
pre {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
pre {
|
||||
/* TODO is !important really needed because of Prism? */
|
||||
background: var(--bg1) !important;
|
||||
overflow: auto;
|
||||
|
||||
& code {
|
||||
background: none;
|
||||
}
|
||||
}
|
||||
|
||||
blockquote,
|
||||
blockquote.twitter-tweet {
|
||||
border-left: var(--primary-alt) 5px solid;
|
||||
margin: 0.5rem 0;
|
||||
|
||||
& code {
|
||||
background: var(--bg2);
|
||||
}
|
||||
|
||||
& p:first-of-type {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
& p:last-of-type {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
blockquote.twitter-tweet {
|
||||
border-color: var(--blue2);
|
||||
color: inherit;
|
||||
font: inherit;
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
|
||||
& a {
|
||||
color: var(--blue2);
|
||||
}
|
||||
|
||||
& a:hover {
|
||||
color: var(--blue1);
|
||||
text-decoration: none !important;
|
||||
}
|
||||
}
|
@@ -0,0 +1,14 @@
|
||||
pre::-webkit-scrollbar {
|
||||
height: 0.5rem;
|
||||
scrollbar-width: auto;
|
||||
}
|
||||
|
||||
pre::-webkit-scrollbar-track {
|
||||
background: var(--bg2);
|
||||
border-radius: 0.2rem;
|
||||
}
|
||||
|
||||
pre::-webkit-scrollbar-thumb {
|
||||
background: var(--bg4);
|
||||
border-radius: 0.2rem;
|
||||
}
|
@@ -0,0 +1,48 @@
|
||||
.layout {
|
||||
display: grid;
|
||||
grid-template-areas:
|
||||
"header"
|
||||
"main"
|
||||
"footer";
|
||||
grid-template-rows: auto 1fr auto;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
main {
|
||||
align-items: start;
|
||||
display: grid;
|
||||
grid-area: main;
|
||||
grid-template-areas: "empty content sidebar";
|
||||
grid-template-columns: 1fr minmax(0, 650px) 4fr;
|
||||
}
|
||||
|
||||
header {
|
||||
background: var(--bg1);
|
||||
grid-area: header;
|
||||
}
|
||||
|
||||
footer {
|
||||
grid-area: footer;
|
||||
}
|
||||
|
||||
main,
|
||||
footer {
|
||||
margin: 0.5em 1.1em;
|
||||
}
|
||||
|
||||
.content {
|
||||
grid-area: content;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
grid-area: sidebar;
|
||||
margin-top: 3rem;
|
||||
position: sticky;
|
||||
top: 2rem;
|
||||
|
||||
@media (--lg) {
|
||||
display: flex;
|
||||
}
|
||||
}
|
@@ -0,0 +1,285 @@
|
||||
header {
|
||||
display: grid;
|
||||
font-family: var(--font-monospace);
|
||||
font-size: 1.125rem;
|
||||
grid-template-columns: auto auto 1fr auto;
|
||||
grid-template-areas: "heading search nav theme-toggle";
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.logo {
|
||||
color: var(--fg0);
|
||||
display: flex;
|
||||
font-weight: 700;
|
||||
grid-area: heading;
|
||||
|
||||
&:hover .logo__cursor {
|
||||
animation: 1s blink infinite;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.logo__chevron,
|
||||
.logo__cursor {
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
.logo__cursor {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.logo__text {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media (--md) {
|
||||
.logo__text {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
/*! purgecss start ignore */
|
||||
|
||||
.search {
|
||||
display: flex;
|
||||
grid-area: search;
|
||||
margin: 0 1rem;
|
||||
}
|
||||
|
||||
#search__text {
|
||||
border: 1px solid var(--bg2);
|
||||
border-radius: 0.2rem;
|
||||
background: var(--bg2);
|
||||
caret-color: var(--fg);
|
||||
color: var(--fg);
|
||||
outline: none;
|
||||
padding: 0 0.5rem;
|
||||
width: 100%;
|
||||
|
||||
&:hover {
|
||||
border-color: var(--bg3);
|
||||
}
|
||||
|
||||
&:focus {
|
||||
border-color: var(--bg4);
|
||||
}
|
||||
|
||||
&::placeholder {
|
||||
color: var(--fg3);
|
||||
}
|
||||
|
||||
&[type="search"]::-webkit-search-cancel-button {
|
||||
appearance: none;
|
||||
}
|
||||
}
|
||||
|
||||
#search__suggestions {
|
||||
background: var(--bg);
|
||||
border-radius: 0.2rem;
|
||||
box-shadow: 0 0.5rem 1rem var(--bg1);
|
||||
font-family: var(--font-serif);
|
||||
left: 0;
|
||||
margin-top: 2rem;
|
||||
position: absolute;
|
||||
width: 95vw;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
@media (--md) {
|
||||
.search {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#search__suggestions {
|
||||
width: 60vw;
|
||||
}
|
||||
}
|
||||
|
||||
.search__suggestions--hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.search__suggestion-item {
|
||||
border-bottom: 1px dashed var(--bg2);
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 2fr;
|
||||
|
||||
&:focus,
|
||||
&:focus-visible,
|
||||
&:hover {
|
||||
background: var(--bg1);
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
.search__suggestion-title,
|
||||
.search__suggestion-description {
|
||||
padding: 0 1rem;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
.search__suggestion-title {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.search__suggestion-description {
|
||||
border-left: 1px solid var(--bg2);
|
||||
}
|
||||
|
||||
.search__no-results {
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
/*! purgecss end ignore */
|
||||
|
||||
.theme__toggle {
|
||||
align-items: center;
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--yellow1);
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
grid-area: theme-toggle;
|
||||
margin: 0 1rem;
|
||||
|
||||
&:hover {
|
||||
color: var(--yellow2);
|
||||
}
|
||||
|
||||
& svg {
|
||||
height: 28px;
|
||||
width: 28px;
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: simplify deep nesting */
|
||||
nav#menu {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
grid-area: nav;
|
||||
justify-content: flex-end;
|
||||
|
||||
& .menu__item {
|
||||
color: var(--fg);
|
||||
|
||||
&:hover {
|
||||
color: var(--fg3);
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
& ul {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
& ul.menu--horizontal {
|
||||
align-items: center;
|
||||
display: none;
|
||||
|
||||
& li {
|
||||
display: inline-block;
|
||||
margin: 0 0.75rem;
|
||||
}
|
||||
|
||||
@media (--md) {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
& ul.menu--vertical {
|
||||
background: var(--fg0);
|
||||
bottom: 0;
|
||||
margin: 0;
|
||||
padding: 3rem;
|
||||
position: fixed;
|
||||
right: 0;
|
||||
top: 0;
|
||||
transform: translate(100%, 0);
|
||||
transition: transform 0.5s cubic-bezier(0.9, 0, 0.1, 1);
|
||||
width: 50%;
|
||||
z-index: 10;
|
||||
|
||||
& .menu__item {
|
||||
color: var(--bg1);
|
||||
|
||||
&:hover {
|
||||
color: var(--bg4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
& .menu__burger {
|
||||
display: flex;
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
|
||||
& > * {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
& svg {
|
||||
width: inherit;
|
||||
z-index: 20;
|
||||
height: inherit;
|
||||
|
||||
& line {
|
||||
transition-duration: 0.5s;
|
||||
transition-property: stroke, opacity, transform;
|
||||
transition-timing-function: cubic-bezier(0.9, 0, 0.1, 1);
|
||||
}
|
||||
|
||||
& line:nth-of-type(1) {
|
||||
transform-origin: center 6px;
|
||||
}
|
||||
|
||||
& line:nth-of-type(2) {
|
||||
transform-origin: center 12px;
|
||||
}
|
||||
|
||||
& line:nth-of-type(3) {
|
||||
transform-origin: center 18px;
|
||||
}
|
||||
}
|
||||
|
||||
& input {
|
||||
height: inherit;
|
||||
opacity: 0;
|
||||
width: inherit;
|
||||
z-index: 30;
|
||||
|
||||
&:checked {
|
||||
& ~ ul.menu--vertical {
|
||||
transform: none;
|
||||
}
|
||||
|
||||
& ~ svg {
|
||||
stroke: var(--bg1);
|
||||
|
||||
& line:nth-of-type(1) {
|
||||
transform: translate(0, 6px) rotate(45deg);
|
||||
}
|
||||
|
||||
& line:nth-of-type(2) {
|
||||
opacity: 0;
|
||||
transform: scale(0.2);
|
||||
}
|
||||
|
||||
& line:nth-of-type(3) {
|
||||
transform: translate(0, -6px) rotate(-45deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (--md) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,83 @@
|
||||
.sidebar {
|
||||
font-family: var(--font-monospace);
|
||||
max-width: 350px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding-left: 2.5rem;
|
||||
|
||||
& hr {
|
||||
margin: 1.5rem auto;
|
||||
}
|
||||
|
||||
& svg {
|
||||
fill: var(--fg);
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar__heading {
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
aside.toc {
|
||||
& a {
|
||||
color: var(--primary-alt);
|
||||
}
|
||||
|
||||
& a:hover {
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
& ul {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
& ul {
|
||||
font-size: 0.9rem;
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
& li {
|
||||
line-height: 1.1;
|
||||
|
||||
& a {
|
||||
display: block;
|
||||
padding: 0.2rem 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.jr-basics__image {
|
||||
background: var(--bg1);
|
||||
border: 2px solid var(--bg2);
|
||||
}
|
||||
|
||||
.jr-basics__summary {
|
||||
color: var(--fg3);
|
||||
font-family: var(--font-serif);
|
||||
margin: 0.75rem 0;
|
||||
}
|
||||
|
||||
.jr-basics__profile {
|
||||
& a:hover {
|
||||
color: var(--fg3);
|
||||
|
||||
& svg {
|
||||
fill: var(--fg3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tag-cloud {
|
||||
line-height: 1.1;
|
||||
text-align: justify;
|
||||
}
|
||||
|
||||
.tag-cloud__tag:hover {
|
||||
color: var(--fg3);
|
||||
}
|
||||
|
||||
.tag-cloud__tag--active {
|
||||
text-decoration: underline;
|
||||
}
|
@@ -0,0 +1,75 @@
|
||||
.post,
|
||||
.content-section {
|
||||
border-bottom: 2px dotted var(--bg1);
|
||||
padding: 2rem 0;
|
||||
}
|
||||
|
||||
.post {
|
||||
& figure,
|
||||
& img:not(figure img),
|
||||
& video:not(figure video) {
|
||||
margin: 0.5rem 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
|
||||
.post-header,
|
||||
.post-content__read-more {
|
||||
font-family: var(--font-monospace);
|
||||
}
|
||||
|
||||
.post-meta__author {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.post-content {
|
||||
margin: 1.3rem 0;
|
||||
}
|
||||
|
||||
.post-content__read-more {
|
||||
color: var(--primary-alt);
|
||||
margin-top: 1.3rem;
|
||||
}
|
||||
|
||||
.post-header,
|
||||
.post-content {
|
||||
& a {
|
||||
color: var(--primary-alt);
|
||||
}
|
||||
|
||||
& a:hover {
|
||||
color: var(--primary);
|
||||
}
|
||||
}
|
||||
|
||||
.post-tags {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.9rem;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
.post-tag {
|
||||
font-size: 0.9rem;
|
||||
line-height: 1;
|
||||
|
||||
&::before {
|
||||
content: "#";
|
||||
}
|
||||
}
|
||||
|
||||
.post-heading__anchor {
|
||||
display: none;
|
||||
}
|
||||
|
||||
h1:hover,
|
||||
h2:hover,
|
||||
h3:hover,
|
||||
h4:hover,
|
||||
h5:hover,
|
||||
h6:hover {
|
||||
& .post-heading__anchor {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
.jr__item-meta {
|
||||
font-family: var(--font-monospace);
|
||||
}
|
||||
|
||||
.jr__item-meta {
|
||||
align-items: start;
|
||||
flex-flow: column;
|
||||
}
|
||||
|
||||
@media (--md) {
|
||||
.jr__item-meta {
|
||||
align-items: center;
|
||||
flex-flow: row wrap;
|
||||
}
|
||||
|
||||
.jr__date,
|
||||
.jr__date-range,
|
||||
.jr-work__location {
|
||||
flex-grow: 1;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.jr-awards__awarder,
|
||||
.jr-publications__publisher,
|
||||
.jr-education__institution,
|
||||
.jr-volunteer__organization {
|
||||
flex-basis: 100%;
|
||||
}
|
||||
}
|
@@ -0,0 +1,68 @@
|
||||
.social-share {
|
||||
align-items: center;
|
||||
border-top: 2px dotted var(--bg1);
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.9rem;
|
||||
margin: 3rem 0;
|
||||
padding-top: 3rem;
|
||||
|
||||
& svg {
|
||||
fill: var(--fg);
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
|
||||
&.icon-tabler {
|
||||
fill: none;
|
||||
stroke: var(--fg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.social-share__item {
|
||||
background: var(--bg1);
|
||||
padding: 0.5rem;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
/* Sticky social bar left
|
||||
|
||||
@media (--xl) {
|
||||
.social-share {
|
||||
align-items: flex-start;
|
||||
border-top: none;
|
||||
flex-direction: column;
|
||||
|
||||
position: fixed;
|
||||
top: 15%;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.social-share__heading {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.social-share__item {
|
||||
transition: padding 0.2s ease-in;
|
||||
|
||||
&:hover {
|
||||
padding: 0.5rem 1rem;
|
||||
}
|
||||
|
||||
& svg {
|
||||
&:hover {
|
||||
fill: var(--fg);
|
||||
}
|
||||
|
||||
&.icon-tabler {
|
||||
fill: none;
|
||||
|
||||
&:hover {
|
||||
stroke: var(--fg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
@@ -0,0 +1,24 @@
|
||||
/*! purgecss start ignore */
|
||||
|
||||
/* Prism Plugins */
|
||||
{{ range $.Site.Params.prism.plugins }}
|
||||
{{ $path := printf "prismjs/plugins/%s/prism-%s.css" . . }}
|
||||
{{ $plugin := resources.Get $path }}
|
||||
{{ if $plugin }}
|
||||
{{ printf "/*%s*/" $plugin }}
|
||||
@import "{{ $plugin }}";
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
/* Prism Font */
|
||||
code,
|
||||
kbd,
|
||||
code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
font-family: var(--font-monospace);
|
||||
}
|
||||
|
||||
/*! purgecss end ignore */
|
||||
|
||||
/* Default license header for non-vendor CSS source code that follows */
|
||||
/*! MIT License | github.com/schnerring/hugo-theme-gruvbox */
|
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
Bootstrap 5 breakpoints
|
||||
See: https://getbootstrap.com/docs/5.0/layout/breakpoints/#available-breakpoints
|
||||
*/
|
||||
@custom-media --sm (min-width: 576px);
|
||||
@custom-media --md (min-width: 768px);
|
||||
@custom-media --lg (min-width: 992px);
|
||||
@custom-media --xl (min-width: 1200px);
|
||||
@custom-media --xxl (min-width: 1400px);
|
@@ -0,0 +1,11 @@
|
||||
footer {
|
||||
align-items: center;
|
||||
color: var(--fg3);
|
||||
display: flex;
|
||||
font-family: var(--font-monospace);
|
||||
font-size: 0.8rem;
|
||||
justify-content: center;
|
||||
padding-bottom: 0.5rem;
|
||||
padding-top: 2rem;
|
||||
text-align: center;
|
||||
}
|
@@ -0,0 +1,18 @@
|
||||
.pagination {
|
||||
display: flex;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.pagination__button {
|
||||
color: var(--primary-alt);
|
||||
font-family: var(--font-monospace);
|
||||
font-size: 1.125rem;
|
||||
}
|
||||
|
||||
.pagination__button:hover {
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
.pagination__button--next {
|
||||
margin-left: auto;
|
||||
}
|
@@ -0,0 +1,47 @@
|
||||
function getTheme() {
|
||||
if (localStorage && localStorage.getItem("theme")) {
|
||||
// User preference
|
||||
return localStorage.getItem("theme");
|
||||
}
|
||||
if (window.matchMedia) {
|
||||
// OS preference
|
||||
return window.matchMedia("(prefers-color-scheme: light)").matches
|
||||
? "light"
|
||||
: "dark";
|
||||
}
|
||||
// Undefined
|
||||
}
|
||||
|
||||
function setTheme(theme) {
|
||||
// Main theme
|
||||
document.documentElement.setAttribute("data-theme", theme);
|
||||
|
||||
// Prism theme
|
||||
const prismDark = document.getElementById("prism-dark");
|
||||
const prismLight = document.getElementById("prism-light");
|
||||
prismDark.toggleAttribute("disabled", theme === "light");
|
||||
prismLight.toggleAttribute("disabled", theme === "dark");
|
||||
|
||||
// Store user preference
|
||||
localStorage.setItem("theme", theme);
|
||||
}
|
||||
|
||||
// Initial load
|
||||
const theme = getTheme();
|
||||
if (theme) setTheme(theme);
|
||||
|
||||
function toggleTheme(e) {
|
||||
const theme = e.currentTarget.classList.contains("light--hidden")
|
||||
? "light"
|
||||
: "dark";
|
||||
setTheme(theme);
|
||||
}
|
||||
|
||||
// This script is inlined in the <head> of the document, so we have to wait
|
||||
// for the DOM content before can add event listeners to the toggle buttons
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
const toggleButtons = document.querySelectorAll(".theme__toggle");
|
||||
toggleButtons.forEach((btn) => {
|
||||
btn.addEventListener("click", toggleTheme);
|
||||
});
|
||||
});
|
@@ -0,0 +1,137 @@
|
||||
//! Source: https://github.com/h-enk/doks/blob/master/assets/js/index.js
|
||||
|
||||
import { Document } from "flexsearch";
|
||||
|
||||
const search = document.getElementById("search__text");
|
||||
const suggestions = document.getElementById("search__suggestions");
|
||||
|
||||
if (search !== null) {
|
||||
document.addEventListener("keydown", (e) => {
|
||||
if (e.ctrlKey && e.key === "/") {
|
||||
// Focus search bar with CTRL + /
|
||||
e.preventDefault();
|
||||
search.focus();
|
||||
} else if (e.key === "Escape") {
|
||||
// Unfocus search bar with ESC
|
||||
search.blur();
|
||||
suggestions.classList.add("search__suggestions--hidden");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener("click", (e) => {
|
||||
const clickInsideSuggestions = suggestions.contains(e.target);
|
||||
if (!clickInsideSuggestions) {
|
||||
// Hide search suggestions if clicking elsewhere
|
||||
suggestions.classList.add("search__suggestions--hidden");
|
||||
}
|
||||
});
|
||||
|
||||
/*! Source: https://dev.to/shubhamprakash/trap-focus-using-javascript-6a3 */
|
||||
document.addEventListener("keydown", (e) => {
|
||||
const suggestionsHidden = suggestions.classList.contains(
|
||||
"search__suggestions--hidden"
|
||||
);
|
||||
if (suggestionsHidden) return;
|
||||
|
||||
const focusableSuggestions = [...suggestions.querySelectorAll("a")];
|
||||
if (focusableSuggestions.length === 0) return;
|
||||
|
||||
const currentIndex = focusableSuggestions.indexOf(document.activeElement);
|
||||
|
||||
if (e.key === "ArrowDown") {
|
||||
// Focus next suggestion
|
||||
e.preventDefault();
|
||||
const nextIndex =
|
||||
currentIndex + 1 < focusableSuggestions.length
|
||||
? currentIndex + 1
|
||||
: currentIndex;
|
||||
focusableSuggestions[nextIndex].focus();
|
||||
} else if (e.key === "ArrowUp") {
|
||||
// Focus previous suggestion
|
||||
e.preventDefault();
|
||||
nextIndex = currentIndex > 0 ? currentIndex - 1 : 0;
|
||||
focusableSuggestions[nextIndex].focus();
|
||||
}
|
||||
});
|
||||
|
||||
(function () {
|
||||
const index = new Document({
|
||||
tokenize: "forward",
|
||||
cache: 100,
|
||||
document: {
|
||||
id: "id",
|
||||
store: ["href", "title", "description"],
|
||||
index: ["title", "description", "content"],
|
||||
},
|
||||
});
|
||||
|
||||
//! Source: https://discourse.gohugo.io/t/range-length-or-last-element/3803/2
|
||||
{{ $list := (where .Site.RegularPages "Type" "in" .Site.Params.mainSections) }}
|
||||
{{ $len := (len $list) }}
|
||||
|
||||
index.add(
|
||||
{{ range $index, $element := $list }}
|
||||
{
|
||||
id: {{ $index }},
|
||||
href: "{{ .RelPermalink }}",
|
||||
title: {{ .Title | jsonify }},
|
||||
{{ with .Description }}
|
||||
description: {{ . | jsonify }},
|
||||
{{ else }}
|
||||
description: {{ .Summary | plainify | jsonify }},
|
||||
{{ end }}
|
||||
content: {{ .Plain | jsonify }}
|
||||
})
|
||||
{{ if ne (add $index 1) $len }}
|
||||
.add(
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ if eq 0 $len }}
|
||||
)
|
||||
{{ end }}
|
||||
;
|
||||
|
||||
search.addEventListener("input", function () {
|
||||
const maxResultsCount = {{ $.Site.Params.flexsearch.maxResultsCount | default 5 }};
|
||||
const searchText = this.value;
|
||||
const searchResults = index.search(searchText, maxResultsCount, { enrich: true });
|
||||
const searchResultsMap = new Map();
|
||||
|
||||
// Deduplicate search results by href
|
||||
for (const searchResult of searchResults.flatMap((r) => r.result)) {
|
||||
if (searchResultsMap.has(searchResult.href)) continue;
|
||||
searchResultsMap.set(searchResult.doc.href, searchResult.doc);
|
||||
}
|
||||
|
||||
suggestions.innerHTML = "";
|
||||
suggestions.classList.remove("search__suggestions--hidden");
|
||||
|
||||
if (searchResultsMap.size === 0 && searchText) {
|
||||
const noResultsMessage = document.createElement("div")
|
||||
noResultsMessage.innerHTML = `No results for "<strong>${searchText}</strong>"`
|
||||
noResultsMessage.classList.add("search__no-results");
|
||||
suggestions.appendChild(noResultsMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
for (const [href, searchResult] of searchResultsMap) {
|
||||
const suggestion = document.createElement("a");
|
||||
suggestion.href = href;
|
||||
suggestion.classList.add("search__suggestion-item");
|
||||
suggestions.appendChild(suggestion);
|
||||
|
||||
const title = document.createElement("div");
|
||||
title.textContent = searchResult.title;
|
||||
title.classList.add("search__suggestion-title");
|
||||
suggestion.appendChild(title);
|
||||
|
||||
const description = document.createElement("div");
|
||||
description.textContent = searchResult.description;
|
||||
description.classList.add("search__suggestion-description");
|
||||
suggestion.appendChild(description);
|
||||
|
||||
if (suggestions.childElementCount === maxResultsCount) break;
|
||||
}
|
||||
});
|
||||
})();
|
@@ -0,0 +1,11 @@
|
||||
import Prism from "prismjs";
|
||||
|
||||
{{ range $.Site.Params.prism.languages }}
|
||||
import "prismjs/components/prism-{{ . }}";
|
||||
{{ end }}
|
||||
|
||||
{{ range $.Site.Params.prism.plugins }}
|
||||
import "prismjs/plugins/{{ . }}/prism-{{ . }}";
|
||||
{{ end }}
|
||||
|
||||
Prism.highlightAll();
|
@@ -0,0 +1,2 @@
|
||||
noJSConfigInAssets = true
|
||||
writeStats = true
|
@@ -0,0 +1,150 @@
|
||||
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
|
||||
|
||||
[markup]
|
||||
[markup.goldmark]
|
||||
[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
|
||||
# if the content isn't trustworthy.
|
||||
unsafe = true
|
||||
|
||||
[imaging]
|
||||
# JPEG and WebP image processing quality, defaults to 75%
|
||||
#quality = 75
|
||||
|
||||
[params]
|
||||
# dark or light, defaults to light. Local storage and OS preference override this param. For more details see:
|
||||
# https://github.com/schnerring/hugo-theme-gruvbox/issues/34#issuecomment-1235870375
|
||||
#defaultTheme = "light"
|
||||
# gray red green yellow blue purple aqua orange, defaults to blue
|
||||
#themeColor = "blue"
|
||||
# soft medium hard, defaults to medium
|
||||
#themeContrast = "medium"
|
||||
author = "Michael Schnerring"
|
||||
subtitle = "Theme Demo"
|
||||
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."
|
||||
|
||||
[params.logo]
|
||||
text = "gruvbox"
|
||||
url = "/"
|
||||
|
||||
[params.prism]
|
||||
languages = [
|
||||
"markup",
|
||||
"css",
|
||||
"clike",
|
||||
"javascript",
|
||||
"bash",
|
||||
"diff",
|
||||
"toml"
|
||||
]
|
||||
plugins = [
|
||||
"normalize-whitespace",
|
||||
"toolbar",
|
||||
"copy-to-clipboard",
|
||||
"line-numbers",
|
||||
"command-line",
|
||||
"diff-highlight"
|
||||
]
|
||||
|
||||
# By default, the theme creates resized versions of images ranging from 300 to
|
||||
# 700 pixels wide in increments of 200 pixels
|
||||
#[params.imageResize]
|
||||
# min = 300
|
||||
# max = 700
|
||||
# increment = 200
|
||||
|
||||
[params.tagCloud]
|
||||
enable = false
|
||||
minFontSizeRem = 0.8
|
||||
maxFontSizeRem = 2.0
|
||||
|
||||
# Social share links for posts:
|
||||
# - iconSuite: "simple-icon" or "tabler-icon"
|
||||
# - iconName: name of the icon from the "iconSuite"
|
||||
# - {url} placeholder for post .Permalink
|
||||
# - {title} placeholder for post .Title
|
||||
# See https://github.com/bradvin/social-share-urls for more format strings
|
||||
[[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 = "simple-icon"
|
||||
iconName = "twitter"
|
||||
formatString = "https://twitter.com/intent/tweet?url={url}&text={title}"
|
||||
[[params.socialShare]]
|
||||
iconSuite = "simple-icon"
|
||||
iconName = "linkedin"
|
||||
formatString = "https://www.linkedin.com/sharing/share-offsite/?url={url}"
|
||||
[[params.socialShare]]
|
||||
iconSuite = "simple-icon"
|
||||
iconName = "whatsapp"
|
||||
formatString = "whatsapp://send/?text={title}%20{url}"
|
||||
[[params.socialShare]]
|
||||
iconSuite = "simple-icon"
|
||||
iconName = "tumblr"
|
||||
formatString = "https://www.tumblr.com/widgets/share/tool?canonicalUrl={url}&title={title}&caption={title}"
|
||||
[[params.socialShare]]
|
||||
iconSuite = "simple-icon"
|
||||
iconName = "pinterest"
|
||||
formatString = "http://pinterest.com/pin/create/button/?url={url}"
|
||||
[[params.socialShare]]
|
||||
iconSuite = "simple-icon"
|
||||
iconName = "ycombinator"
|
||||
formatString = "https://news.ycombinator.com/submitlink?u={url}&t={title}"
|
||||
[[params.socialShare]]
|
||||
iconSuite = "simple-icon"
|
||||
iconName = "vk"
|
||||
formatString = "http://vk.com/share.php?url={url}&title={title}&comment={title}"
|
||||
[[params.socialShare]]
|
||||
iconSuite = "simple-icon"
|
||||
iconName = "xing"
|
||||
formatString = "https://www.xing.com/spi/shares/new?url={url}"
|
||||
[[params.socialShare]]
|
||||
iconSuite = "simple-icon"
|
||||
iconName = "telegram"
|
||||
formatString = "https://telegram.me/share/url?url={url}&text={title}"
|
||||
[[params.socialShare]]
|
||||
iconSuite = "tabler-icon"
|
||||
iconName = "mail"
|
||||
formatString = "mailto:?subject={title}&body={url}"
|
||||
|
||||
[menu]
|
||||
[[menu.main]]
|
||||
identifier = "blog"
|
||||
name = "Blog"
|
||||
url = "/blog"
|
||||
weight = 10
|
||||
[[menu.main]]
|
||||
identifier = "cv"
|
||||
name = "CV"
|
||||
url = "/cv"
|
||||
weight = 20
|
||||
[[menu.main]]
|
||||
identifier = "about"
|
||||
name = "About"
|
||||
url = "/about"
|
||||
weight = 30
|
||||
|
||||
[languages]
|
||||
[languages.en]
|
||||
languageName = "English"
|
||||
weight = 10
|
||||
[languages.en.params.jsonResume]
|
||||
present = "present"
|
||||
[languages.de]
|
||||
languageName = "Deutsch"
|
||||
weight = 20
|
||||
[languages.de.params.jsonResume]
|
||||
present = "heute"
|
@@ -0,0 +1,44 @@
|
||||
# Module debugging
|
||||
#replacements = "github.com/schnerring/hugo-mod-json-resume -> ../../hugo-mod-json-resume"
|
||||
[hugoVersion]
|
||||
extended = true
|
||||
min = "0.84.0"
|
||||
[[imports]]
|
||||
path = "github.com/schnerring/hugo-mod-json-resume"
|
||||
[[imports.mounts]]
|
||||
source = "data"
|
||||
target = "data"
|
||||
[[imports.mounts]]
|
||||
source = "layouts"
|
||||
target = "layouts"
|
||||
[[imports.mounts]]
|
||||
source = "assets/css/json-resume.css"
|
||||
target = "assets/css/critical/44-json-resume.css"
|
||||
[[mounts]]
|
||||
# required by hugo-mod-json-resume
|
||||
source = "node_modules/simple-icons/icons"
|
||||
target = "assets/simple-icons"
|
||||
[[mounts]]
|
||||
source = "assets"
|
||||
target = "assets"
|
||||
[[mounts]]
|
||||
source = "layouts"
|
||||
target = "layouts"
|
||||
[[mounts]]
|
||||
source = "static"
|
||||
target = "static"
|
||||
[[mounts]]
|
||||
source = "node_modules/prismjs"
|
||||
target = "assets/prismjs"
|
||||
[[mounts]]
|
||||
source = "node_modules/prism-themes/themes"
|
||||
target = "assets/prism-themes"
|
||||
[[mounts]]
|
||||
source = "node_modules/typeface-fira-code/files"
|
||||
target = "static/fonts"
|
||||
[[mounts]]
|
||||
source = "node_modules/typeface-roboto-slab/files"
|
||||
target = "static/fonts"
|
||||
[[mounts]]
|
||||
source = "node_modules/@tabler/icons/icons"
|
||||
target = "assets/tabler-icons"
|
@@ -0,0 +1,3 @@
|
||||
category = "categories"
|
||||
tag = "tags"
|
||||
series = "series"
|
@@ -0,0 +1 @@
|
||||
baseURL = "https://hugo-theme-gruvbox.schnerring.net"
|
@@ -0,0 +1,26 @@
|
||||
---
|
||||
title: "About"
|
||||
draft: false
|
||||
---
|
||||
|
||||
## Attributions
|
||||
|
||||
This theme depends on the following projects:
|
||||
|
||||
- [Powered by Hugo](https://gohugo.io/)
|
||||
- Color scheme based on [Gruvbox](https://github.com/morhetz/gruvbox)
|
||||
- Code Highlighting by [Prism](https://prismjs.com/)
|
||||
- [Tabler Icons](https://tablericons.com/)
|
||||
- [Simple Icons](https://simpleicons.org/)
|
||||
- Content with the [#hugo-basic-example](/tags/hugo-basic-example) tag
|
||||
originates from [gohugoio/hugoBasicExample](https://github.com/gohugoio/hugoBasicExample)
|
||||
|
||||
A big thanks to the creators! ❤️
|
||||
|
||||
The [profile picture of Richard Hendricks is from the Fandom Silicon Valley Wiki](https://silicon-valley.fandom.com/wiki/Richard_Hendricks?file=Richard_Hendricks.jpg).
|
||||
|
||||
## Legal
|
||||
|
||||
The theme is [licensed under MIT](https://github.com/schnerring/hugo-theme-gruvbox/blob/main/LICENSE).
|
||||
|
||||
All trademarks are the property of their respective owners.
|
@@ -0,0 +1,65 @@
|
||||
---
|
||||
title: "Embed Video Files"
|
||||
date: "2022-04-26T01:16:18+02:00"
|
||||
draft: false
|
||||
comments: false
|
||||
socialShare: true
|
||||
toc: false
|
||||
---
|
||||
|
||||
Use the [video shortcode](https://github.com/schnerring/hugo-theme-gruvbox/blob/main/layouts/shortcodes/video.html)
|
||||
to embed your video files from [Hugo Page Resources](https://gohugo.io/content-management/page-resources/).
|
||||
|
||||
{{< video src="my-video" autoplay="true" controls="false" loop="true" >}}
|
||||
|
||||
<!--more-->
|
||||
|
||||
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)
|
After Width: | Height: | Size: 7.8 KiB |
@@ -0,0 +1,47 @@
|
||||
+++
|
||||
author = "Hugo Authors"
|
||||
title = "Emoji Support"
|
||||
date = "2019-03-05"
|
||||
description = "Guide to emoji usage in Hugo"
|
||||
tags = [
|
||||
"emoji",
|
||||
"hugo-basic-example",
|
||||
]
|
||||
+++
|
||||
|
||||
Emoji can be enabled in a Hugo project in a number of ways.
|
||||
<!--more-->
|
||||
The [`emojify`](https://gohugo.io/functions/emojify/) function can be called directly in templates or [Inline Shortcodes](https://gohugo.io/templates/shortcode-templates/#inline-shortcodes).
|
||||
|
||||
To enable emoji globally, set `enableEmoji` to `true` in your site's [configuration](https://gohugo.io/getting-started/configuration/) and then you can type emoji shorthand codes directly in content files; e.g.
|
||||
|
||||
<p><span class="nowrap"><span class="emojify">🙈</span> <code>:see_no_evil:</code></span> <span class="nowrap"><span class="emojify">🙉</span> <code>:hear_no_evil:</code></span> <span class="nowrap"><span class="emojify">🙊</span> <code>:speak_no_evil:</code></span></p>
|
||||
<br>
|
||||
|
||||
The [Emoji cheat sheet](http://www.emoji-cheat-sheet.com/) is a useful reference for emoji shorthand codes.
|
||||
|
||||
***
|
||||
|
||||
**N.B.** The above steps enable Unicode Standard emoji characters and sequences in Hugo, however the rendering of these glyphs depends on the browser and the platform. To style the emoji you can either use a third party emoji font or a font stack; e.g.
|
||||
|
||||
{{< highlight html >}}
|
||||
.emoji {
|
||||
font-family: Apple Color Emoji, Segoe UI Emoji, NotoColorEmoji, Segoe UI Symbol, Android Emoji, EmojiSymbols;
|
||||
}
|
||||
{{< /highlight >}}
|
||||
|
||||
{{< css.inline >}}
|
||||
<style>
|
||||
.emojify {
|
||||
font-family: Apple Color Emoji, Segoe UI Emoji, NotoColorEmoji, Segoe UI Symbol, Android Emoji, EmojiSymbols;
|
||||
font-size: 2rem;
|
||||
vertical-align: middle;
|
||||
}
|
||||
@media screen and (max-width:650px) {
|
||||
.nowrap {
|
||||
display: block;
|
||||
margin: 25px 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
{{< /css.inline >}}
|
After Width: | Height: | Size: 4.0 MiB |
After Width: | Height: | Size: 2.3 MiB |
@@ -0,0 +1,82 @@
|
||||
---
|
||||
title: "Image Optimization"
|
||||
date: "2021-10-16T23:51:37+02:00"
|
||||
comments: false
|
||||
socialShare: true
|
||||
toc: true
|
||||
cover:
|
||||
src: ./alexandre-van-thuan-mr9FouttLGY-unsplash.jpg
|
||||
alt: The interior of Stadsbiblioteket in Stockholm - Gunnar Asplunds library from 1928. The architecture is a transition between neoclassicism and functionalism.
|
||||
caption: By [Alexandre Van Thuan](https://unsplash.com/photos/mr9FouttLGY)
|
||||
---
|
||||
|
||||
The theme optimizes images by default with a custom [Hugo's markdown render hook](https://gohugo.io/getting-started/configuration-markup#markdown-render-hooks):
|
||||
|
||||
- The theme creates resized versions for each image, ranging from 100 to 700
|
||||
pixels wide.
|
||||
- It generates [WebP](https://en.wikipedia.org/wiki/WebP) versions for each size
|
||||
if the original image format isn't WebP.
|
||||
- The theme keeps the original file format as a fallback for browsers that
|
||||
[don't support the WebP format](https://caniuse.com/webp).
|
||||
- Images in SVG format are embedded as-is.
|
||||
|
||||
## Blog Post Cover Images
|
||||
|
||||
Use the [front matter](https://gohugo.io/content-management/front-matter/) of
|
||||
your posts to add cover images:
|
||||
|
||||
<!-- markdownlint-disable MD013 -->
|
||||
|
||||
```markdown
|
||||
---
|
||||
cover:
|
||||
src: alexandre-van-thuan-mr9FouttLGY-unsplash.jpg
|
||||
alt: The interior of Stadsbiblioteket in Stockholm - Gunnar Asplunds library from 1928. The architecture is a transition between neoclassicism and functionalism.
|
||||
caption: By [Alexandre Van Thuan](https://unsplash.com/photos/mr9FouttLGY)
|
||||
---
|
||||
```
|
||||
|
||||
<!-- markdownlint-enable MD013 -->
|
||||
|
||||
## Captions
|
||||
|
||||
Add captions to your inline images like this:
|
||||
|
||||
```markdown
|
||||
---
|
||||

|
||||
---
|
||||
```
|
||||
|
||||
")
|
||||
|
||||
## JPEG and WebP Quality
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
## Resizing
|
||||
|
||||
By default, the theme creates resized versions of images ranging from 300 to 700
|
||||
pixels wide in increments of 100 pixels. Override the resize behavior by
|
||||
adding the following to the `config.toml` file:
|
||||
|
||||
```toml
|
||||
[params]
|
||||
[params.imageResize]
|
||||
min = 300
|
||||
max = 700
|
||||
increment = 100
|
||||
```
|
||||
|
||||
## Lazy Loading
|
||||
|
||||
Images are lazily loaded by default using the `loading="lazy"` attribute on
|
||||
HTML `img` tags.
|
||||
|
||||
{{< video src="lazy-loading" autoplay="true" controls="false" loop="true" >}}
|
After Width: | Height: | Size: 61 KiB |
@@ -0,0 +1,149 @@
|
||||
+++
|
||||
author = "Hugo Authors"
|
||||
title = "Markdown Syntax Guide"
|
||||
date = "2019-03-11"
|
||||
description = "Sample article showcasing basic Markdown syntax and formatting for HTML elements."
|
||||
tags = [
|
||||
"markdown",
|
||||
"css",
|
||||
"html",
|
||||
"hugo-basic-example",
|
||||
]
|
||||
categories = [
|
||||
"themes",
|
||||
"syntax",
|
||||
]
|
||||
series = ["Themes Guide"]
|
||||
aliases = ["migrate-from-jekyl"]
|
||||
+++
|
||||
|
||||
This article offers a sample of basic Markdown syntax that can be used in Hugo content files, also it shows whether basic HTML elements are decorated with CSS in a Hugo theme.
|
||||
<!--more-->
|
||||
|
||||
## Headings
|
||||
|
||||
The following HTML `<h1>`—`<h6>` elements represent six levels of section headings. `<h1>` is the highest section level while `<h6>` is the lowest.
|
||||
|
||||
# H1
|
||||
## H2
|
||||
### H3
|
||||
#### H4
|
||||
##### H5
|
||||
###### H6
|
||||
|
||||
## Paragraph
|
||||
|
||||
Xerum, quo qui aut unt expliquam qui dolut labo. Aque venitatiusda cum, voluptionse latur sitiae dolessi aut parist aut dollo enim qui voluptate ma dolestendit peritin re plis aut quas inctum laceat est volestemque commosa as cus endigna tectur, offic to cor sequas etum rerum idem sintibus eiur? Quianimin porecus evelectur, cum que nis nust voloribus ratem aut omnimi, sitatur? Quiatem. Nam, omnis sum am facea corem alique molestrunt et eos evelece arcillit ut aut eos eos nus, sin conecerem erum fuga. Ri oditatquam, ad quibus unda veliamenimin cusam et facea ipsamus es exerum sitate dolores editium rerore eost, temped molorro ratiae volorro te reribus dolorer sperchicium faceata tiustia prat.
|
||||
|
||||
Itatur? Quiatae cullecum rem ent aut odis in re eossequodi nonsequ idebis ne sapicia is sinveli squiatum, core et que aut hariosam ex eat.
|
||||
|
||||
## Blockquotes
|
||||
|
||||
The blockquote element represents content that is quoted from another source, optionally with a citation which must be within a `footer` or `cite` element, and optionally with in-line changes such as annotations and abbreviations.
|
||||
|
||||
#### Blockquote without attribution
|
||||
|
||||
> Tiam, ad mint andaepu dandae nostion secatur sequo quae.
|
||||
> **Note** that you can use *Markdown syntax* within a blockquote.
|
||||
|
||||
#### Blockquote with attribution
|
||||
|
||||
> Don't communicate by sharing memory, share memory by communicating.<br>
|
||||
> — <cite>Rob Pike[^1]</cite>
|
||||
|
||||
[^1]: The above quote is excerpted from Rob Pike's [talk](https://www.youtube.com/watch?v=PAAkCSZUG1c) during Gopherfest, November 18, 2015.
|
||||
|
||||
## Tables
|
||||
|
||||
Tables aren't part of the core Markdown spec, but Hugo supports supports them out-of-the-box.
|
||||
|
||||
Name | Age
|
||||
--------|------
|
||||
Bob | 27
|
||||
Alice | 23
|
||||
|
||||
#### Inline Markdown within tables
|
||||
|
||||
| Italics | Bold | Code |
|
||||
| -------- | -------- | ------ |
|
||||
| *italics* | **bold** | `code` |
|
||||
|
||||
## Code Blocks
|
||||
|
||||
#### Code block with backticks
|
||||
|
||||
```html
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Example HTML5 Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>Test</p>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
#### Code block indented with four spaces
|
||||
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Example HTML5 Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>Test</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
#### Code block with Hugo's internal highlight shortcode
|
||||
{{< highlight html >}}
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Example HTML5 Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>Test</p>
|
||||
</body>
|
||||
</html>
|
||||
{{< /highlight >}}
|
||||
|
||||
## List Types
|
||||
|
||||
#### Ordered List
|
||||
|
||||
1. First item
|
||||
2. Second item
|
||||
3. Third item
|
||||
|
||||
#### Unordered List
|
||||
|
||||
* List item
|
||||
* Another item
|
||||
* And another item
|
||||
|
||||
#### Nested list
|
||||
|
||||
* Fruit
|
||||
* Apple
|
||||
* Orange
|
||||
* Banana
|
||||
* Dairy
|
||||
* Milk
|
||||
* Cheese
|
||||
|
||||
## Other Elements — abbr, sub, sup, kbd, mark
|
||||
|
||||
<abbr title="Graphics Interchange Format">GIF</abbr> is a bitmap image format.
|
||||
|
||||
H<sub>2</sub>O
|
||||
|
||||
X<sup>n</sup> + Y<sup>n</sup> = Z<sup>n</sup>
|
||||
|
||||
Press <kbd><kbd>CTRL</kbd>+<kbd>ALT</kbd>+<kbd>Delete</kbd></kbd> to end the session.
|
||||
|
||||
Most <mark>salamanders</mark> are nocturnal, and hunt for insects, worms, and other small creatures.
|
@@ -0,0 +1,51 @@
|
||||
---
|
||||
author: Hugo Authors
|
||||
title: Math Typesetting
|
||||
date: 2019-03-08
|
||||
description: A brief guide to setup KaTeX
|
||||
math: true
|
||||
tags:
|
||||
- "hugo-basic-example"
|
||||
---
|
||||
|
||||
Mathematical notation in a Hugo project can be enabled by using third party JavaScript libraries.
|
||||
<!--more-->
|
||||
|
||||
In this example we will be using [KaTeX](https://katex.org/)
|
||||
|
||||
- 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:
|
||||
|
||||
```bash
|
||||
{{ if or .Params.math .Site.Params.math }}
|
||||
{{ partial "math.html" . }}
|
||||
{{ end }}
|
||||
```
|
||||
|
||||
- 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/katex@0.11.1/dist/katex.min.css" integrity="sha384-zB1R0rpPzHqg7Kpt0Aljp8JPLqbXI3bhnPWROx27a9N0Ll6ZP/+DiW/UqRcLbRjq" crossorigin="anonymous">
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.11.1/dist/katex.min.js" integrity="sha384-y23I5Q6l+B6vatafAwxRu/0oK/79VlbSz7Q9aiSZUvyWYIYsd+qj+o24G5ZU2zJz" crossorigin="anonymous"></script>
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.11.1/dist/contrib/auto-render.min.js" integrity="sha384-kWPLUVMOks5AQFrykwIup5lo0m3iMkkHrD0uJ4H5cjeGihAutqP0yW0J6dpFiVkI" crossorigin="anonymous" onload="renderMathInElement(document.body);"></script>
|
||||
{{ end }}
|
||||
{{</ math.inline >}}
|
||||
|
||||
### Examples
|
||||
|
||||
{{< math.inline >}}
|
||||
<p>
|
||||
Inline math: \(\varphi = \dfrac{1+\sqrt5}{2}= 1.6180339887…\)
|
||||
</p>
|
||||
{{</ math.inline >}}
|
||||
|
||||
Block math:
|
||||
$$
|
||||
\varphi = 1+\frac{1} {1+\frac{1} {1+\frac{1} {1+\cdots} } }
|
||||
$$
|
@@ -0,0 +1,46 @@
|
||||
+++
|
||||
author = "Hugo Authors"
|
||||
title = "Placeholder Text"
|
||||
date = "2019-03-09"
|
||||
description = "Lorem Ipsum Dolor Si Amet"
|
||||
tags = [
|
||||
"markdown",
|
||||
"text",
|
||||
"hugo-basic-example",
|
||||
]
|
||||
+++
|
||||
|
||||
Lorem est tota propiore conpellat pectoribus de pectora summo. <!--more-->Redit teque digerit hominumque toris verebor lumina non cervice subde tollit usus habet Arctonque, furores quas nec ferunt. Quoque montibus nunc caluere tempus inhospita parcite confusaque translucet patri vestro qui optatis lumine cognoscere flos nubis! Fronde ipsamque patulos Dryopen deorum.
|
||||
|
||||
1. Exierant elisi ambit vivere dedere
|
||||
2. Duce pollice
|
||||
3. Eris modo
|
||||
4. Spargitque ferrea quos palude
|
||||
|
||||
Rursus nulli murmur; hastile inridet ut ab gravi sententia! Nomine potitus silentia flumen, sustinet placuit petis in dilapsa erat sunt. Atria tractus malis.
|
||||
|
||||
1. Comas hunc haec pietate fetum procerum dixit
|
||||
2. Post torum vates letum Tiresia
|
||||
3. Flumen querellas
|
||||
4. Arcanaque montibus omnes
|
||||
5. Quidem et
|
||||
|
||||
# Vagus elidunt
|
||||
|
||||
<svg class="canon" xmlns="http://www.w3.org/2000/svg" overflow="visible" viewBox="0 0 496 373" height="373" width="496"><g fill="none"><path stroke="#000" stroke-width=".75" d="M.599 372.348L495.263 1.206M.312.633l494.95 370.853M.312 372.633L247.643.92M248.502.92l246.76 370.566M330.828 123.869V1.134M330.396 1.134L165.104 124.515"></path><path stroke="#ED1C24" stroke-width=".75" d="M275.73 41.616h166.224v249.05H275.73zM54.478 41.616h166.225v249.052H54.478z"></path><path stroke="#000" stroke-width=".75" d="M.479.375h495v372h-495zM247.979.875v372"></path><ellipse cx="498.729" cy="177.625" rx=".75" ry="1.25"></ellipse><ellipse cx="247.229" cy="377.375" rx=".75" ry="1.25"></ellipse></g></svg>
|
||||
|
||||
[The Van de Graaf Canon](https://en.wikipedia.org/wiki/Canons_of_page_construction#Van_de_Graaf_canon)
|
||||
|
||||
## Mane refeci capiebant unda mulcebat
|
||||
|
||||
Victa caducifer, malo vulnere contra dicere aurato, ludit regale, voca! Retorsit colit est profanae esse virescere furit nec; iaculi matertera et visa est, viribus. Divesque creatis, tecta novat collumque vulnus est, parvas. **Faces illo pepulere** tempus adest. Tendit flamma, ab opes virum sustinet, sidus sequendo urbis.
|
||||
|
||||
Iubar proles corpore raptos vero auctor imperium; sed et huic: manus caeli Lelegas tu lux. Verbis obstitit intus oblectamina fixis linguisque ausus sperare Echionides cornuaque tenent clausit possit. Omnia putatur. Praeteritae refert ausus; ferebant e primus lora nutat, vici quae mea ipse. Et iter nil spectatae vulnus haerentia iuste et exercebat, sui et.
|
||||
|
||||
Eurytus Hector, materna ipsumque ut Politen, nec, nate, ignari, vernum cohaesit sequitur. Vel **mitis temploque** vocatus, inque alis, *oculos nomen* non silvis corpore coniunx ne displicet illa. Crescunt non unus, vidit visa quantum inmiti flumina mortis facto sic: undique a alios vincula sunt iactata abdita! Suspenderat ego fuit tendit: luna, ante urbem Propoetides **parte**.
|
||||
|
||||
{{< css.inline >}}
|
||||
<style>
|
||||
.canon { background: white; width: 100%; height: auto; }
|
||||
</style>
|
||||
{{< /css.inline >}}
|
@@ -0,0 +1,243 @@
|
||||
---
|
||||
title: "Prism Code Highlighting Showcase"
|
||||
date: "2021-07-28T04:25:37+02:00"
|
||||
comments: false
|
||||
socialShare: true
|
||||
toc: true
|
||||
---
|
||||
|
||||
This theme uses [Prism](https://prismjs.com/) for code highlighting. Other Hugo
|
||||
themes usually include a pre-configured version of Prism, which complicates
|
||||
updates and clutters the source code base with third-party JavaScript.
|
||||
|
||||
Only the Prism features you select in the Hugo site configuration are bundled by
|
||||
the build process. This way, Prism can be easily updated with `npm` and the
|
||||
size of the JavaScript and CSS bundles are minimized by only including what you
|
||||
need.
|
||||
|
||||
<!--more-->
|
||||
|
||||
Here is a an example configuration demonstrating how to configure `languages`
|
||||
and `plugins` in the `config.toml` file of your Hugo site:
|
||||
|
||||
```toml
|
||||
[params]
|
||||
[params.prism]
|
||||
languages = [
|
||||
"markup",
|
||||
"css",
|
||||
"clike",
|
||||
"javascript"
|
||||
]
|
||||
plugins = [
|
||||
"normalize-whitespace",
|
||||
"toolbar",
|
||||
"copy-to-clipboard"
|
||||
]
|
||||
```
|
||||
|
||||
## Languages
|
||||
|
||||
The following languages are available:
|
||||
|
||||
<!-- markdownlint-disable MD033 -->
|
||||
<pre class="language-none" style="max-height: 500px">
|
||||
<code>
|
||||
{{% prism-features "languages" %}}
|
||||
</code>
|
||||
</pre>
|
||||
<!-- markdownlint-enable MD033 -->
|
||||
|
||||
## Plugins
|
||||
|
||||
Before using a plugin in production, read its documentation and test it
|
||||
thoroughly. E.g., the [`remove-initial-line-feed` plugin](https://prismjs.com/plugins/remove-initial-line-feed/)
|
||||
is still available despite being deprecated in favor of [`normalize-whitespace`](https://prismjs.com/plugins/normalize-whitespace/).
|
||||
|
||||
Many Prism plugins require using `<pre>` tags with custom attributes. Hugo uses
|
||||
Goldmark as Markdown handler, which by default doesn't render raw inline HTML,
|
||||
so make sure to enable [`unsafe`](https://gohugo.io/getting-started/configuration-markup#goldmark)
|
||||
rendering if required:
|
||||
|
||||
```toml
|
||||
[markup]
|
||||
[markup.goldmark]
|
||||
[markup.goldmark.renderer]
|
||||
unsafe = true
|
||||
```
|
||||
|
||||
The following plugins are available:
|
||||
|
||||
```none
|
||||
{{% prism-features "plugins" %}}
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
#### Copy to Clipboard
|
||||
|
||||
`copy-to-clipboard` requires the `toolbar` plugin, so make sure to add it
|
||||
**after** adding `toolbar` in the `config.toml` file:
|
||||
|
||||
Config:
|
||||
|
||||
```toml
|
||||
[params.prism]
|
||||
# ...
|
||||
plugins = [
|
||||
"toolbar",
|
||||
"copy-to-clipboard"
|
||||
]
|
||||
```
|
||||
|
||||
#### Line Numbers
|
||||
|
||||
Config:
|
||||
|
||||
```toml
|
||||
[params.prism]
|
||||
plugins = [
|
||||
"line-numbers"
|
||||
]
|
||||
```
|
||||
|
||||
Input:
|
||||
|
||||
```html
|
||||
<pre class="line-numbers">
|
||||
<code>
|
||||
Example
|
||||
</code>
|
||||
</pre>
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
<!-- markdownlint-disable MD033 -->
|
||||
<pre class="line-numbers language-none" data-start="42">
|
||||
<code>
|
||||
Hello,
|
||||
World!
|
||||
|
||||
Foo
|
||||
Bar
|
||||
</code>
|
||||
</pre>
|
||||
<!-- markdownlint-enable MD033 -->
|
||||
|
||||
#### Command Line
|
||||
|
||||
Config:
|
||||
|
||||
```toml
|
||||
[params.prism]
|
||||
languages = [
|
||||
"bash"
|
||||
]
|
||||
plugins = [
|
||||
"command-line"
|
||||
]
|
||||
```
|
||||
|
||||
Input:
|
||||
|
||||
```html
|
||||
<pre class="command-line language-bash" data-user="root" data-host="localhost">
|
||||
<code>
|
||||
cd /usr/local/etc
|
||||
cp php.ini php.ini.bak
|
||||
vi php.ini
|
||||
</code>
|
||||
</pre>
|
||||
|
||||
<pre
|
||||
class="command-line language-bash"
|
||||
data-user="chris"
|
||||
data-host="remotehost"
|
||||
data-output="2, 4-8"
|
||||
>
|
||||
<code>
|
||||
pwd
|
||||
/usr/home/chris/bin
|
||||
ls -la
|
||||
total 2
|
||||
drwxr-xr-x 2 chris chris 11 Jan 10 16:48 .
|
||||
drwxr--r-x 45 chris chris 92 Feb 14 11:10 ..
|
||||
-rwxr-xr-x 1 chris chris 444 Aug 25 2013 backup
|
||||
-rwxr-xr-x 1 chris chris 642 Jan 17 14:42 deploy
|
||||
</code>
|
||||
</pre>
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
<!-- markdownlint-disable MD033 -->
|
||||
<pre class="command-line language-bash" data-user="root" data-host="localhost">
|
||||
<code>
|
||||
cd /usr/local/etc
|
||||
cp php.ini php.ini.bak
|
||||
vi php.ini
|
||||
</code>
|
||||
</pre>
|
||||
|
||||
<pre
|
||||
class="command-line language-bash"
|
||||
data-user="chris"
|
||||
data-host="remotehost"
|
||||
data-output="2, 4-8"
|
||||
>
|
||||
<code>
|
||||
pwd
|
||||
/usr/home/chris/bin
|
||||
ls -la
|
||||
total 2
|
||||
drwxr-xr-x 2 chris chris 11 Jan 10 16:48 .
|
||||
drwxr--r-x 45 chris chris 92 Feb 14 11:10 ..
|
||||
-rwxr-xr-x 1 chris chris 444 Aug 25 2013 backup
|
||||
-rwxr-xr-x 1 chris chris 642 Jan 17 14:42 deploy
|
||||
</code>
|
||||
</pre>
|
||||
<!-- markdownlint-enable MD033 -->
|
||||
|
||||
#### Diff Highlight
|
||||
|
||||
Config:
|
||||
|
||||
```toml
|
||||
[params.prism]
|
||||
languages = [
|
||||
"javascript",
|
||||
"diff"
|
||||
]
|
||||
plugins = [
|
||||
"diff-highlight"
|
||||
]
|
||||
```
|
||||
|
||||
Input:
|
||||
|
||||
```html
|
||||
<pre class="language-diff-javascript diff-highlight">
|
||||
<code>
|
||||
@@ -4,6 +4,5 @@
|
||||
- let foo = bar.baz([1, 2, 3]);
|
||||
- foo = foo + 1;
|
||||
+ const foo = bar.baz([1, 2, 3]) + 1;
|
||||
console.log(`foo: ${foo}`);
|
||||
</code>
|
||||
</pre>
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
<!-- markdownlint-disable MD033 -->
|
||||
<pre class="language-diff-javascript diff-highlight">
|
||||
<code>
|
||||
@@ -4,6 +4,5 @@
|
||||
- let foo = bar.baz([1, 2, 3]);
|
||||
- foo = foo + 1;
|
||||
+ const foo = bar.baz([1, 2, 3]) + 1;
|
||||
console.log(`foo: ${foo}`);
|
||||
</code>
|
||||
</pre>
|
||||
<!-- markdownlint-enable MD033 -->
|
@@ -0,0 +1,35 @@
|
||||
+++
|
||||
author = "Hugo Authors"
|
||||
title = "Rich Content"
|
||||
date = "2019-03-10"
|
||||
description = "A brief description of Hugo Shortcodes"
|
||||
tags = [
|
||||
"shortcodes",
|
||||
"privacy",
|
||||
"hugo-basic-example",
|
||||
]
|
||||
+++
|
||||
|
||||
Hugo ships with several [Built-in Shortcodes](https://gohugo.io/content-management/shortcodes/#use-hugos-built-in-shortcodes) for rich content, along with a [Privacy Config](https://gohugo.io/about/hugo-and-gdpr/) and a set of Simple Shortcodes that enable static and no-JS versions of various social media embeds.
|
||||
<!--more-->
|
||||
---
|
||||
|
||||
## YouTube Privacy Enhanced Shortcode
|
||||
|
||||
{{< youtube ZJthWmvUzzc >}}
|
||||
|
||||
<br>
|
||||
|
||||
---
|
||||
|
||||
## Twitter Simple Shortcode
|
||||
|
||||
{{< twitter_simple user="DesignReviewed" id="1085870671291310081" >}}
|
||||
|
||||
<br>
|
||||
|
||||
---
|
||||
|
||||
## Vimeo Simple Shortcode
|
||||
|
||||
{{< vimeo_simple 48912912 >}}
|
@@ -0,0 +1,49 @@
|
||||
---
|
||||
title: "Lebenslauf"
|
||||
draft: false
|
||||
type: "cv"
|
||||
---
|
||||
|
||||
## Erfahrung
|
||||
|
||||
{{< json-resume "work" >}}
|
||||
|
||||
## Ausbildung
|
||||
|
||||
{{< json-resume "education" >}}
|
||||
|
||||
## Ehrenamt
|
||||
|
||||
{{< json-resume "volunteer" >}}
|
||||
|
||||
## Auszeichnungen
|
||||
|
||||
{{< json-resume "awards" >}}
|
||||
|
||||
## Zertifikate
|
||||
|
||||
{{< json-resume "certificates" >}}
|
||||
|
||||
## Publikationen
|
||||
|
||||
{{< json-resume "publications" >}}
|
||||
|
||||
## Fähigkeiten
|
||||
|
||||
{{< json-resume "skills" >}}
|
||||
|
||||
## Sprachen
|
||||
|
||||
{{< json-resume "languages" >}}
|
||||
|
||||
## Interessen
|
||||
|
||||
{{< json-resume "interests" >}}
|
||||
|
||||
## Referenzen
|
||||
|
||||
{{< json-resume "references" >}}
|
||||
|
||||
## Projekte
|
||||
|
||||
{{< json-resume "projects" >}}
|
@@ -0,0 +1,49 @@
|
||||
---
|
||||
title: "CV"
|
||||
draft: false
|
||||
type: "cv"
|
||||
---
|
||||
|
||||
## Experience
|
||||
|
||||
{{< json-resume "work" >}}
|
||||
|
||||
## Education
|
||||
|
||||
{{< json-resume "education" >}}
|
||||
|
||||
## Volunteering
|
||||
|
||||
{{< json-resume "volunteer" >}}
|
||||
|
||||
## Awards
|
||||
|
||||
{{< json-resume "awards" >}}
|
||||
|
||||
## Certificates
|
||||
|
||||
{{< json-resume "certificates" >}}
|
||||
|
||||
## Publications
|
||||
|
||||
{{< json-resume "publications" >}}
|
||||
|
||||
## Skills
|
||||
|
||||
{{< json-resume "skills" >}}
|
||||
|
||||
## Languages
|
||||
|
||||
{{< json-resume "languages" >}}
|
||||
|
||||
## Interests
|
||||
|
||||
{{< json-resume "interests" >}}
|
||||
|
||||
## References
|
||||
|
||||
{{< json-resume "references" >}}
|
||||
|
||||
## Projects
|
||||
|
||||
{{< json-resume "projects" >}}
|
@@ -0,0 +1,155 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/jsonresume/resume-schema/v1.0.0/schema.json",
|
||||
"basics": {
|
||||
"name": "Richard Hendricks",
|
||||
"label": "Programmer",
|
||||
"image": "https://hugo-theme-gruvbox.schnerring.net/richard-hendricks.webp",
|
||||
"email": "richard.hendricks@piedpiper.com",
|
||||
"phone": "(912) 555-4321",
|
||||
"summary": "Richard hails from Tulsa. He has earned degrees from the University of Oklahoma and Stanford. Before starting Pied Piper, he worked for Hooli as a part time software developer. While his work focuses on applied information theory, mostly optimizing lossless compression schema of both the length-limited and adaptive variants, his non-work interests range widely, everything from quantum computing to chaos theory.",
|
||||
"location": {
|
||||
"city": "San Francisco"
|
||||
},
|
||||
"profiles": [
|
||||
{
|
||||
"network": "GitHub",
|
||||
"username": "hugo-theme-gruvbox",
|
||||
"url": "https://github.com/schnerring/hugo-theme-gruvbox"
|
||||
},
|
||||
{
|
||||
"network": "GitHub",
|
||||
"username": "hugo-mod-json-resume",
|
||||
"url": "https://github.com/schnerring/hugo-mod-json-resume"
|
||||
},
|
||||
{
|
||||
"network": "Twitter",
|
||||
"url": "https://twitter.com/SiliconHBO"
|
||||
},
|
||||
{
|
||||
"network": "fandom",
|
||||
"url": "https://silicon-valley.fandom.com/wiki/Richard_Hendricks"
|
||||
},
|
||||
{
|
||||
"network": "HBO",
|
||||
"url": "https://www.hbo.com/silicon-valley"
|
||||
},
|
||||
{
|
||||
"network": "IMDB",
|
||||
"url": "https://www.imdb.com/title/tt2575988/"
|
||||
},
|
||||
{
|
||||
"network": "Wikipedia",
|
||||
"url": "https://en.wikipedia.org/wiki/List_of_Silicon_Valley_characters#Richard_Hendricks"
|
||||
}
|
||||
]
|
||||
},
|
||||
"work": [
|
||||
{
|
||||
"name": "Pied Piper",
|
||||
"location": "Palo Alto, CA",
|
||||
"description": "Awesome compression company",
|
||||
"position": "CEO/President",
|
||||
"url": "http://piedpiper.com",
|
||||
"startDate": "2013-12-01",
|
||||
"endDate": "2014-12-01",
|
||||
"summary": "Pied Piper is a multi-platform technology based on a proprietary universal compression algorithm that has consistently fielded high Weisman Scores™ that are not merely competitive, but approach the theoretical limit of lossless compression.",
|
||||
"highlights": [
|
||||
"Build an algorithm for artist to detect if their music was violating copy right infringement laws",
|
||||
"Successfully won Techcrunch Disrupt",
|
||||
"Optimized an algorithm that holds the current world record for Weisman Scores"
|
||||
]
|
||||
}
|
||||
],
|
||||
"volunteer": [
|
||||
{
|
||||
"organization": "CoderDojo",
|
||||
"position": "Teacher",
|
||||
"url": "http://coderdojo.example.com/",
|
||||
"startDate": "2012-01-01",
|
||||
"endDate": "2013-01-01",
|
||||
"summary": "Global movement of free coding clubs for young people.",
|
||||
"highlights": ["Awarded 'Teacher of the Month'"]
|
||||
}
|
||||
],
|
||||
"education": [
|
||||
{
|
||||
"institution": "University of Oklahoma",
|
||||
"url": "https://www.ou.edu/",
|
||||
"area": "Information Technology",
|
||||
"studyType": "Bachelor",
|
||||
"startDate": "2011-06-01",
|
||||
"endDate": "2014-01-01",
|
||||
"score": "4.0",
|
||||
"courses": ["DB1101 - Basic SQL", "CS2011 - Java Introduction"]
|
||||
}
|
||||
],
|
||||
"awards": [
|
||||
{
|
||||
"title": "Digital Compression Pioneer Award",
|
||||
"date": "2014-11-01",
|
||||
"awarder": "Techcrunch",
|
||||
"summary": "There is no spoon."
|
||||
}
|
||||
],
|
||||
"publications": [
|
||||
{
|
||||
"name": "Video compression for 3d media",
|
||||
"publisher": "Hooli",
|
||||
"releaseDate": "2014-10-01",
|
||||
"url": "http://en.wikipedia.org/wiki/Silicon_Valley_(TV_series)",
|
||||
"summary": "Innovative middle-out compression algorithm that changes the way we store data."
|
||||
}
|
||||
],
|
||||
"skills": [
|
||||
{
|
||||
"name": "Web Development",
|
||||
"level": "Master",
|
||||
"keywords": ["HTML", "CSS", "Javascript"]
|
||||
},
|
||||
{
|
||||
"name": "Compression",
|
||||
"level": "Master",
|
||||
"keywords": ["Mpeg", "MP4", "GIF"]
|
||||
}
|
||||
],
|
||||
"languages": [
|
||||
{
|
||||
"language": "English",
|
||||
"fluency": "Native speaker"
|
||||
}
|
||||
],
|
||||
"interests": [
|
||||
{
|
||||
"name": "Wildlife",
|
||||
"keywords": ["Ferrets", "Unicorns"]
|
||||
}
|
||||
],
|
||||
"references": [
|
||||
{
|
||||
"name": "Erlich Bachman",
|
||||
"reference": "It is my pleasure to recommend Richard, his performance working as a consultant for Main St. Company proved that he will be a valuable addition to any company."
|
||||
}
|
||||
],
|
||||
"projects": [
|
||||
{
|
||||
"name": "Miss Direction",
|
||||
"description": "A mapping engine that misguides you",
|
||||
"highlights": [
|
||||
"Won award at AIHacks 2016",
|
||||
"Built by all women team of newbie programmers",
|
||||
"Using modern technologies such as GoogleMaps, Chrome Extension and Javascript"
|
||||
],
|
||||
"keywords": ["GoogleMaps", "Chrome Extension", "Javascript"],
|
||||
"startDate": "2016-08-24",
|
||||
"endDate": "2016-08-24",
|
||||
"roles": ["Team lead", "Designer"],
|
||||
"entity": "Smoogle",
|
||||
"type": "application"
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"canonical": "https://raw.githubusercontent.com/jsonresume/resume-schema/master/resume.json",
|
||||
"version": "v1.0.0",
|
||||
"lastModified": "2017-12-24T15:53:00"
|
||||
}
|
||||
}
|
5
themes/github.com/davegallant/hugo-theme-gruvbox/go.mod
Normal file
@@ -0,0 +1,5 @@
|
||||
module github.com/davegallant/hugo-theme-gruvbox
|
||||
|
||||
go 1.21
|
||||
|
||||
require github.com/schnerring/hugo-mod-json-resume v0.0.0-20231022202951-552402b37357 // indirect
|
2
themes/github.com/davegallant/hugo-theme-gruvbox/go.sum
Normal file
@@ -0,0 +1,2 @@
|
||||
github.com/schnerring/hugo-mod-json-resume v0.0.0-20231022202951-552402b37357 h1:FR5kIQJNpHrB+P6yb8PrDVO8FpbUxF5fdTXLQp7UUpI=
|
||||
github.com/schnerring/hugo-mod-json-resume v0.0.0-20231022202951-552402b37357/go.mod h1:an+FdylzRESQ2N+NuFK+iLerxnDRWbOqkxCDUXflGF4=
|
@@ -0,0 +1,125 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="512"
|
||||
height="512"
|
||||
viewBox="0 0 135.46666 135.46667"
|
||||
version="1.1"
|
||||
id="svg46266"
|
||||
sodipodi:docname="favicon_inkscape.svg"
|
||||
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<title
|
||||
id="title83640">hugo-theme-gruvbox</title>
|
||||
<sodipodi:namedview
|
||||
id="namedview46268"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:document-units="mm"
|
||||
showgrid="false"
|
||||
units="px"
|
||||
inkscape:zoom="0.77771465"
|
||||
inkscape:cx="242.37682"
|
||||
inkscape:cy="297.02411"
|
||||
inkscape:window-width="1278"
|
||||
inkscape:window-height="1368"
|
||||
inkscape:window-x="3833"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="layer2" />
|
||||
<defs
|
||||
id="defs46263">
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath62400">
|
||||
<rect
|
||||
style="display:inline;fill:#282828;stroke-width:0.264583"
|
||||
id="rect62402"
|
||||
width="67.73333"
|
||||
height="135.46666"
|
||||
x="67.733345"
|
||||
y="3.5603841e-06" />
|
||||
</clipPath>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath62404">
|
||||
<rect
|
||||
style="fill:#282828;stroke-width:0.264583"
|
||||
id="rect62406"
|
||||
width="67.73333"
|
||||
height="135.46666"
|
||||
x="0"
|
||||
y="3.5603841e-06" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
<g
|
||||
inkscape:label="light"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
style="display:inline">
|
||||
<rect
|
||||
style="fill:#fbf1c7;stroke-width:0.264583;fill-opacity:1"
|
||||
id="rect62128-5"
|
||||
width="67.73333"
|
||||
height="135.46666"
|
||||
x="0"
|
||||
y="3.5603841e-06" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:158.75px;line-height:1.25;font-family:'Fira Code';-inkscape-font-specification:'Fira Code';stroke-width:0.264583;fill:#282828;fill-opacity:1"
|
||||
x="18.520834"
|
||||
y="97.141769"
|
||||
id="text48067"
|
||||
clip-path="url(#clipPath62404)"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan48065"
|
||||
style="font-size:158.75px;stroke-width:0.264583;fill:#282828;fill-opacity:1"
|
||||
x="18.520834"
|
||||
y="97.141769">g</tspan></text>
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer2"
|
||||
inkscape:label="dark"
|
||||
style="display:inline">
|
||||
<rect
|
||||
style="fill:#282828;stroke-width:0.264583"
|
||||
id="rect62128-6"
|
||||
width="67.73333"
|
||||
height="135.46666"
|
||||
x="67.733337"
|
||||
y="3.5603841e-06" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:158.75px;line-height:1.25;font-family:'Fira Code';-inkscape-font-specification:'Fira Code';fill:#fbf1c7;fill-opacity:1;stroke-width:0.264583"
|
||||
x="18.520834"
|
||||
y="97.141769"
|
||||
id="text48067-2"
|
||||
clip-path="url(#clipPath62400)"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan48065-4"
|
||||
style="font-size:158.75px;fill:#fbf1c7;fill-opacity:1;stroke-width:0.264583"
|
||||
x="18.520834"
|
||||
y="97.141769">g</tspan></text>
|
||||
</g>
|
||||
<metadata
|
||||
id="metadata83638">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:title>hugo-theme-gruvbox</dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
</svg>
|
After Width: | Height: | Size: 3.7 KiB |
@@ -0,0 +1 @@
|
||||
<svg width="512" height="512" version="1.1" viewBox="0 0 135.47 135.47" xmlns="http://www.w3.org/2000/svg"><title>hugo-theme-gruvbox</title><defs><clipPath id="b"><rect x="67.733" y="3.5604e-6" width="67.733" height="135.47" fill="#282828" stroke-width=".26458"/></clipPath><clipPath id="a"><rect y="3.5604e-6" width="67.733" height="135.47" fill="#282828" stroke-width=".26458"/></clipPath></defs><g stroke-width=".26458"><rect y="3.5604e-6" width="67.733" height="135.47" fill="#fbf1c7"/><text x="18.520834" y="97.141769" clip-path="url(#a)" fill="#282828" font-family="'Fira Code'" font-size="158.75px" style="line-height:1.25" xml:space="preserve"><tspan x="18.520834" y="97.141769" fill="#282828" font-size="158.75px" stroke-width=".26458">g</tspan></text><rect x="67.733" y="3.5604e-6" width="67.733" height="135.47" fill="#282828"/><text x="18.520834" y="97.141769" clip-path="url(#b)" fill="#fbf1c7" font-family="'Fira Code'" font-size="158.75px" style="line-height:1.25" xml:space="preserve"><tspan x="18.520834" y="97.141769" fill="#fbf1c7" font-size="158.75px" stroke-width=".26458">g</tspan></text></g></svg>
|
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 861 KiB |
BIN
themes/github.com/davegallant/hugo-theme-gruvbox/images/tn.png
Normal file
After Width: | Height: | Size: 362 KiB |
@@ -0,0 +1,8 @@
|
||||
{{ define "main" }}
|
||||
<article class="post">
|
||||
<h1>{{ .Title | markdownify }}</h1>
|
||||
<div class="post-content">
|
||||
<p>This is not the page you're looking for.</p>
|
||||
</div>
|
||||
</article>
|
||||
{{ end }}
|
@@ -0,0 +1,4 @@
|
||||
<h{{ .Level }} id="{{ .Anchor | safeURL }}">
|
||||
{{- .Text | safeHTML -}}
|
||||
<a href="#{{ .Anchor | safeURL }}" class="post-heading__anchor" aria-hidden="true">#</a>
|
||||
</h{{ .Level }}>
|
@@ -0,0 +1 @@
|
||||
{{ partial "image.html" (dict "src" .Destination "alt" .PlainText "caption" .Title "page" .Page "lazy" true) }}
|
@@ -0,0 +1,13 @@
|
||||
{{- $isExternal := strings.HasPrefix .Destination "http" -}}
|
||||
<a
|
||||
href="{{ .Destination | safeURL }}"
|
||||
{{ with .Title }}
|
||||
title="{{ . }}"
|
||||
{{ end }}
|
||||
{{ if $isExternal }}
|
||||
class="link--external" target="_blank" rel="noreferrer"
|
||||
{{ end }}
|
||||
>
|
||||
{{- .Text | safeHTML -}}
|
||||
</a>
|
||||
{{- /* Trimm trailing whitespace */ -}}
|
@@ -0,0 +1,19 @@
|
||||
<!DOCTYPE html>
|
||||
<html
|
||||
lang="{{ .Site.Language.Lang | default "en" }}"
|
||||
data-theme="{{ .Param "defaultTheme" | default "light" }}"
|
||||
>
|
||||
{{ partial "head/head.html" . }}
|
||||
<body>
|
||||
<div class="layout">
|
||||
{{ partial "header.html" . }}
|
||||
<main>
|
||||
<div class="content">
|
||||
{{ block "main" . }}{{ end }}
|
||||
</div>
|
||||
{{ partial "sidebar.html" . }}
|
||||
</main>
|
||||
{{ partial "footer.html" . }}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@@ -0,0 +1,9 @@
|
||||
{{ define "main" }}
|
||||
<div class="content-section">
|
||||
<h1>{{ .Title | markdownify }}</h1>
|
||||
{{ with .Content }}
|
||||
<div>{{ . }}</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ partial "post-list.html" .Paginator }}
|
||||
{{ end }}
|
@@ -0,0 +1,20 @@
|
||||
{{ define "main" }}
|
||||
<article class="post">
|
||||
<div class="post-header">
|
||||
<h1>{{ .Title | markdownify }}</h1>
|
||||
{{ partial "post-meta.html" (dict "page" . "pageIndex" 0) }}
|
||||
</div>
|
||||
|
||||
<div class="post-content">
|
||||
{{ .Content }}
|
||||
</div>
|
||||
|
||||
{{ if .Params.SocialShare }}
|
||||
{{ partial "social-share.html" . }}
|
||||
{{ end }}
|
||||
|
||||
{{ if .Params.Comments }}
|
||||
{{ partial "comments.html" . }}
|
||||
{{ end }}
|
||||
</article>
|
||||
{{ end }}
|
@@ -0,0 +1,8 @@
|
||||
{{ define "main" }}
|
||||
<article class="post">
|
||||
<h1>{{ .Title | markdownify }}</h1>
|
||||
<div class="post-content">
|
||||
{{ .Content }}
|
||||
</div>
|
||||
</article>
|
||||
{{ end }}
|
@@ -0,0 +1,12 @@
|
||||
{{ define "main" }}
|
||||
<div class="content-section">
|
||||
<h1>{{ .Title | markdownify }}</h1>
|
||||
{{ with .Content }}
|
||||
<div>{{ . }}</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
<!-- See https://gohugo.io/functions/where/#mainsections -->
|
||||
{{ $pages := where site.RegularPages "Type" "in" site.Params.mainSections }}
|
||||
{{ $paginator := .Paginate $pages }}
|
||||
{{ partial "post-list.html" $paginator }}
|
||||
{{ end }}
|
@@ -0,0 +1,9 @@
|
||||
<!--
|
||||
Comments at the end of posts, e.g.:
|
||||
|
||||
{{ template "_internal/disqus.html" . }}
|
||||
|
||||
|
||||
... or another comment engine.
|
||||
See also: https://gohugo.io/content-management/comments
|
||||
-->
|
@@ -0,0 +1,29 @@
|
||||
<footer>
|
||||
<div class="copyright">
|
||||
{{ with $.Site.Copyright }}
|
||||
{{ . | safeHTML }}
|
||||
{{ end }}
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
{{ $jsBuildOptions := dict "target" "es6" }}
|
||||
{{ if hugo.IsProduction }}
|
||||
{{ $jsBuildOptions = $jsBuildOptions | merge (dict "minify" "true") }}
|
||||
{{ end }}
|
||||
|
||||
{{ $prism := resources.Get "js/prism.js" | resources.ExecuteAsTemplate "js/prism.js" . }}
|
||||
{{ $bundle := slice $prism | resources.Concat "js/main.js" | js.Build $jsBuildOptions }}
|
||||
{{ $flexsearch := resources.Get "js/flexsearch.js" | resources.ExecuteAsTemplate "js/flexsearch.js" . | js.Build $jsBuildOptions }}
|
||||
|
||||
{{ if hugo.IsProduction }}
|
||||
{{ $bundle = $bundle | fingerprint "sha512" }}
|
||||
{{ $flexsearch = $flexsearch | fingerprint "sha512" }}
|
||||
{{ end }}
|
||||
|
||||
{{/* prettier-ignore-start */}}
|
||||
<script src="{{ $bundle.RelPermalink }}"></script>
|
||||
<script src="{{ $flexsearch.RelPermalink }}"></script>
|
||||
{{/* prettier-ignore-end */}}
|
||||
|
||||
<!-- Extensibility -->
|
||||
{{ partial "footer_end.html" . }}
|
@@ -0,0 +1,3 @@
|
||||
<!--
|
||||
Add custom HTML at the end of <body>
|
||||
-->
|
@@ -0,0 +1,10 @@
|
||||
{{ $jsBuildOptions := dict "target" "es6" }}
|
||||
{{ if hugo.IsProduction }}
|
||||
{{ $jsBuildOptions = $jsBuildOptions | merge (dict "minify" "true") }}
|
||||
{{ end }}
|
||||
|
||||
{{ $darkMode := resources.Get "js/dark-mode.js" | js.Build $jsBuildOptions }}
|
||||
|
||||
<script>
|
||||
{{ $darkMode.Content | safeJS }}
|
||||
</script>
|
@@ -0,0 +1,7 @@
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
|
||||
<link rel="manifest" href="/site.webmanifest" />
|
||||
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#282828" />
|
||||
<meta name="msapplication-TileColor" content="#282828" />
|
||||
<meta name="theme-color" content="#282828" />
|
@@ -0,0 +1,21 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
{{ partial "head/resource-hints.html" . }}
|
||||
{{ partial "head/seo.html" . }}
|
||||
|
||||
|
||||
<!-- Extensibility -->
|
||||
{{ partial "head/head_start.html" . }}
|
||||
|
||||
{{ partial "head/stylesheets.html" . }}
|
||||
|
||||
{{ partial "head/dark-mode.html" . }}
|
||||
|
||||
{{ partial "head/favicons.html" . }}
|
||||
|
||||
|
||||
<!-- Extensibility -->
|
||||
{{ partial "head/head_end.html" . }}
|
||||
</head>
|
@@ -0,0 +1,3 @@
|
||||
<!--
|
||||
Add custom HTML at the end of <head>
|
||||
-->
|
@@ -0,0 +1,3 @@
|
||||
<!--
|
||||
Add custom HTML at the start of <head>
|
||||
-->
|
@@ -0,0 +1,42 @@
|
||||
<!-- Preload commonly used font variations -->
|
||||
|
||||
<!-- Roboto Slab -->
|
||||
<link
|
||||
rel="preload"
|
||||
as="font"
|
||||
type="font/woff2"
|
||||
href="/fonts/roboto-slab-latin-400.woff2"
|
||||
crossorigin="anonymous"
|
||||
/>
|
||||
<!-- TODO Use prefetch when more widely supported -->
|
||||
<link
|
||||
rel="preload"
|
||||
as="font"
|
||||
type="font/woff2"
|
||||
href="/fonts/roboto-slab-latin-700.woff2"
|
||||
crossorigin="anonymous"
|
||||
/>
|
||||
|
||||
<!-- Fira Code -->
|
||||
<link
|
||||
rel="preload"
|
||||
as="font"
|
||||
type="font/woff2"
|
||||
href="/fonts/fira-code-latin-300.woff2"
|
||||
crossorigin="anonymous"
|
||||
/>
|
||||
<link
|
||||
rel="preload"
|
||||
as="font"
|
||||
type="font/woff2"
|
||||
href="/fonts/fira-code-latin-400.woff2"
|
||||
crossorigin="anonymous"
|
||||
/>
|
||||
<!-- TODO Use prefetch when more widely supported -->
|
||||
<link
|
||||
rel="preload"
|
||||
as="font"
|
||||
type="font/woff2"
|
||||
href="/fonts/fira-code-latin-700.woff2"
|
||||
crossorigin="anonymous"
|
||||
/>
|
@@ -0,0 +1,55 @@
|
||||
{{ if eq .Kind "404" }}
|
||||
<meta name="robots" content="noindex, follow" />
|
||||
{{ else }}
|
||||
{{ with .Params.robots }}
|
||||
<meta name="robots" content="{{ . }}" />
|
||||
{{ else }}
|
||||
<meta
|
||||
name="robots"
|
||||
content="index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1"
|
||||
/>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{ $title := .Title }}
|
||||
{{ if .IsHome }}
|
||||
{{ $title = .Site.Title }}
|
||||
{{ with .Site.Params.Subtitle }}
|
||||
{{ $title = printf "%s — %s" $title . }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
<title>{{ $title }}</title>
|
||||
|
||||
<meta
|
||||
name="description"
|
||||
content="
|
||||
{{- with .Description -}}
|
||||
{{- . -}}
|
||||
{{- else -}}
|
||||
{{- with .Summary | plainify -}}
|
||||
{{- . -}}
|
||||
{{- else -}}
|
||||
{{- .Site.Params.description -}}
|
||||
{{- end -}}
|
||||
{{- end -}}"
|
||||
/>
|
||||
|
||||
<link rel="canonical" href="{{ .Permalink }}" />
|
||||
|
||||
<!-- Internal Hugo templates -->
|
||||
<!-- See https://gohugo.io/templates/internal -->
|
||||
{{ template "_internal/twitter_cards.html" . }}
|
||||
{{ template "_internal/opengraph.html" . }}
|
||||
{{ template "_internal/schema.html" . }}
|
||||
|
||||
|
||||
<!-- RSS feed -->
|
||||
<!-- See https://gohugo.io/templates/rss/#reference-your-rss-feed-in-head -->
|
||||
{{ range .AlternativeOutputFormats }}
|
||||
<link
|
||||
rel="{{ .Rel }}"
|
||||
type="{{ .MediaType.Type }}"
|
||||
href="{{ .RelPermalink }}"
|
||||
title="{{ $.Site.Title }}"
|
||||
/>
|
||||
{{ end }}
|
@@ -0,0 +1,67 @@
|
||||
<!-- Styles -->
|
||||
{{ $defaultTheme := .Param "defaultTheme" | default "light" }}
|
||||
|
||||
{{ $critical := sort (resources.Match "css/critical/*.css") "Name" | resources.Concat nil | resources.ExecuteAsTemplate nil . | resources.PostCSS }}
|
||||
{{ $nonCritical := sort (resources.Match "css/non-critical/*.css") "Name" | resources.Concat "css/non-critical.css" | resources.ExecuteAsTemplate "css/non-critical.css" . | resources.PostCSS }}
|
||||
{{ $prismDark := resources.Get "prism-themes/prism-gruvbox-dark.css" }}
|
||||
{{ $prismLight := resources.Get "prism-themes/prism-gruvbox-light.css" }}
|
||||
|
||||
{{ if hugo.IsProduction }}
|
||||
{{ $critical = $critical | resources.PostProcess }}
|
||||
{{ $nonCritical = $nonCritical | fingerprint "sha512" | resources.PostProcess }}
|
||||
{{ $prismDark = $prismDark | minify | fingerprint "sha512" }}
|
||||
{{ $prismLight = $prismLight | minify | fingerprint "sha512" }}
|
||||
{{ end }}
|
||||
|
||||
<style>
|
||||
/* stylelint-disable */
|
||||
{{ $critical.Content | safeCSS }}
|
||||
/* stylelint-enable */
|
||||
</style>
|
||||
|
||||
<link
|
||||
rel="preload"
|
||||
href="{{ $nonCritical.RelPermalink }}"
|
||||
as="style"
|
||||
onload="this.onload=null;this.rel='stylesheet'"
|
||||
/>
|
||||
|
||||
<!-- TODO Use prefetch when more widely supported -->
|
||||
<link
|
||||
id="prism-dark"
|
||||
rel="preload"
|
||||
href="{{ $prismDark.RelPermalink }}"
|
||||
as="style"
|
||||
onload="this.onload=null;this.rel='stylesheet'"
|
||||
{{ if eq $defaultTheme "light" }}disabled{{ end }}
|
||||
/>
|
||||
|
||||
<!-- TODO Use prefetch when more widely supported -->
|
||||
<link
|
||||
id="prism-light"
|
||||
rel="preload"
|
||||
href="{{ $prismLight.RelPermalink }}"
|
||||
as="style"
|
||||
onload="this.onload=null;this.rel='stylesheet'"
|
||||
{{ if eq $defaultTheme "dark" }}disabled{{ end }}
|
||||
/>
|
||||
|
||||
<noscript>
|
||||
{{ if eq $defaultTheme "light" }}
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="{{ $prismLight.RelPermalink }}"
|
||||
/>
|
||||
{{ else }}
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="{{ $prismDark.RelPermalink }}"
|
||||
/>
|
||||
{{ end }}
|
||||
|
||||
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="{{ $nonCritical.RelPermalink }}"
|
||||
/>
|
||||
</noscript>
|
@@ -0,0 +1,62 @@
|
||||
<header>
|
||||
<a
|
||||
class="logo"
|
||||
href="
|
||||
{{- with $.Site.Params.Logo.URL -}}
|
||||
{{- . -}}
|
||||
{{- else -}}
|
||||
{{- $.Site.BaseURL -}}
|
||||
{{- end -}}"
|
||||
>
|
||||
{{ with $.Site.Params.Logo.Text }}
|
||||
<div class="logo__text">{{ . }}</div>
|
||||
{{ end }}
|
||||
<div class="logo__chevron">></div>
|
||||
<div class="logo__cursor">█</div>
|
||||
</a>
|
||||
|
||||
<div class="search">
|
||||
<input
|
||||
id="search__text"
|
||||
type="search"
|
||||
placeholder="Search..."
|
||||
aria-label="Search"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<div id="search__suggestions" class="search__suggestions--hidden"></div>
|
||||
</div>
|
||||
|
||||
<nav id="menu">
|
||||
<ul class="menu--horizontal">
|
||||
{{ range $.Site.Menus.main }}
|
||||
<li class="menu__item">
|
||||
<a href="{{ .URL }}">{{ .Name }}</a>
|
||||
</li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
|
||||
<div class="menu__burger">
|
||||
<!-- Invisible checkbox indicating menu state -->
|
||||
<input class="menu__item" type="checkbox" aria-label="Open main menu" />
|
||||
|
||||
{{ partial "icons/tabler-icon.html" "menu-2" }}
|
||||
|
||||
|
||||
<ul class="menu--vertical">
|
||||
{{ range $.Site.Menus.main }}
|
||||
<li>
|
||||
<a class="menu__item" href="{{ .URL }}">{{ .Name }}</a>
|
||||
</li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<button class="theme__toggle light--hidden" aria-label="Toggle light mode">
|
||||
{{ partial "icons/tabler-icon.html" "sun" }}
|
||||
</button>
|
||||
|
||||
<button class="theme__toggle dark--hidden" aria-label="Toggle dark mode">
|
||||
{{ partial "icons/tabler-icon.html" "moon" }}
|
||||
</button>
|
||||
</header>
|
@@ -0,0 +1 @@
|
||||
{{ partial "icons/svg.html" (printf "simple-icons/%s.svg" .) }}
|
@@ -0,0 +1,2 @@
|
||||
{{ $path := lower . }}
|
||||
{{ (resources.Get $path).Content | safeHTML }}
|
@@ -0,0 +1 @@
|
||||
{{ partial "icons/svg.html" (printf "tabler-icons/%s.svg" .) }}
|
@@ -0,0 +1,95 @@
|
||||
<!-- prettier-ignore -->
|
||||
{{ if .caption }}
|
||||
<figure>
|
||||
{{ end }}
|
||||
|
||||
{{ if (strings.HasPrefix .src "http") }}
|
||||
<!-- External image -->
|
||||
<img
|
||||
src="{{ .src }}"
|
||||
alt="{{ .alt }}"
|
||||
{{ with .caption }}title="{{ . | markdownify | plainify }}"{{ end }}
|
||||
{{ if .lazy }}loading="lazy"{{ end }}
|
||||
/>
|
||||
{{ else if (strings.HasPrefix .src "/") }}
|
||||
<!-- Image from static/ -->
|
||||
{{ $imageConfig := imageConfig (path.Join "static" .src) }}
|
||||
<img
|
||||
src="{{ .src }}"
|
||||
alt="{{ .alt }}"
|
||||
{{ with .caption }}title="{{ . | markdownify | plainify }}"{{ end }}
|
||||
{{ if .lazy }}loading="lazy"{{ end }}
|
||||
width="{{ $imageConfig.Width }}"
|
||||
height="{{ $imageConfig.Height }}"
|
||||
/>
|
||||
{{ else }}
|
||||
{{ $src := .src }}
|
||||
{{ if strings.HasPrefix $src "./" }}
|
||||
<!-- Strip "./" prefix from relative path -->
|
||||
{{ $src = substr $src 2 }}
|
||||
{{ end }}
|
||||
<!-- Image from page bundle -->
|
||||
{{ $images := .page.Resources.ByType "image" }}
|
||||
{{ $image := $images.GetMatch $src }}
|
||||
{{ if eq $image.MediaType.SubType "svg" }}
|
||||
<!-- No processing for SVGs -->
|
||||
<img src="{{ $image.RelPermalink }}" alt="{{ .alt }}" />
|
||||
{{ else }}
|
||||
<!-- Calculate resize widths in increments of 100px -->
|
||||
{{ $minWidth := .page.Site.Params.imageResize.min | default 300 }}
|
||||
{{ $maxWidth := .page.Site.Params.imageResize.max | default 700 }}
|
||||
{{ $increment := .page.Site.Params.imageResize.increment | default 200 }}
|
||||
{{ $widths := seq $minWidth $increment $maxWidth }}
|
||||
{{ if lt $image.Width $maxWidth }}
|
||||
{{ $widths = $widths | append $image.Width }}
|
||||
{{ end }}
|
||||
{{ $widthsCount := len $widths }}
|
||||
|
||||
{{ $sizes := slice }}
|
||||
{{ $srcSet := slice }}
|
||||
{{ $webpSrcSet := slice }}
|
||||
{{ range $i, $width := $widths }}
|
||||
{{ if ge $image.Width $width }}
|
||||
{{ if eq $i (sub $widthsCount 1) }}
|
||||
{{ $sizes = $sizes | append (printf "%dpx" $width) }}
|
||||
{{ else }}
|
||||
{{ $maxWidth := (add $width (sub $increment 1)) }}
|
||||
{{ $sizes = $sizes | append (printf "(max-width: %dpx) %dpx" $maxWidth $width) }}
|
||||
{{ end }}
|
||||
{{ $resized := $image.Resize (printf "%dx" $width) }}
|
||||
{{ $srcSet = $srcSet | append (printf "%s %dw" $resized.RelPermalink $resized.Width) }}
|
||||
{{ if not (eq "webp" $image.MediaType.SubType) }}
|
||||
<!-- If image format is not WebP, add conversions -->
|
||||
{{ $webp := $image.Resize (printf "%dx webp" $width) }}
|
||||
{{ $webpSrcSet = $webpSrcSet | append (printf "%s %dw" $webp.RelPermalink $webp.Width) }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
|
||||
<picture>
|
||||
<source
|
||||
type="image/webp"
|
||||
{{ with $webpSrcSet }}srcset="{{ delimit . "," }}"{{ end }}
|
||||
{{ with $sizes }}sizes="{{ delimit . "," }}"{{ end }}
|
||||
/>
|
||||
<img
|
||||
src="{{ $image.RelPermalink }}"
|
||||
{{ with $srcSet }}srcset="{{ delimit . "," }}"{{ end }}
|
||||
{{ with $sizes }}sizes="{{ delimit . "," }}"{{ end }}
|
||||
alt="{{ .alt }}"
|
||||
{{ with .caption }}title="{{ . | markdownify | plainify }}"{{ end }}
|
||||
{{ if .lazy }}loading="lazy"{{ end }}
|
||||
width="{{ $image.Width }}"
|
||||
height="{{ $image.Height }}"
|
||||
/>
|
||||
</picture>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
{{ if .caption }}
|
||||
<figcaption>{{ .page.RenderString .caption }}</figcaption>
|
||||
</figure>
|
||||
{{ end }}
|
@@ -0,0 +1,15 @@
|
||||
<div class="pagination">
|
||||
{{ if .HasPrev }}
|
||||
<span class="pagination__button pagination__button--previous">
|
||||
<a href="{{ .Prev.URL }}">
|
||||
<span><</span>
|
||||
<span>Newer Posts</span>
|
||||
</a>
|
||||
</span>
|
||||
{{ end }}
|
||||
{{ if .HasNext }}
|
||||
<span class="pagination__button pagination__button--next">
|
||||
<a href="{{ .Next.URL }}">Older Posts ></a>
|
||||
</span>
|
||||
{{ end }}
|
||||
</div>
|
@@ -0,0 +1,25 @@
|
||||
{{ range $pageIndex, $page := .Pages }}
|
||||
<article class="post">
|
||||
<div class="post-header">
|
||||
<h2>
|
||||
<a href="{{ .RelPermalink }}">{{ .Title | markdownify }}</a>
|
||||
</h2>
|
||||
{{ partial "post-meta.html" (dict "page" . "pageIndex" $pageIndex) }}
|
||||
</div>
|
||||
|
||||
<div class="post-content">
|
||||
{{ with .Description }}
|
||||
{{ . }}
|
||||
{{ else }}
|
||||
{{ .Summary }}
|
||||
{{ if .Truncated }}
|
||||
<div class="post-content__read-more">
|
||||
<a href="{{ .RelPermalink }}">Read more ></a>
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</div>
|
||||
</article>
|
||||
{{ end }}
|
||||
|
||||
{{ partial "pagination.html" . }}
|
@@ -0,0 +1,27 @@
|
||||
<div class="post-meta">
|
||||
{{- with .page.Date -}}
|
||||
<span>{{ .Format "2006-01-02" }}</span>
|
||||
{{- end -}}
|
||||
{{- with .page.Params.Author -}}
|
||||
<span> by </span><span class="post-meta__author">{{ . }}</span>
|
||||
{{- end -}}
|
||||
{{ with .page.Params.tags }}
|
||||
<div class="post-tags">
|
||||
{{ range . -}}
|
||||
<a class="post-tag" href="{{ urlize (printf "tags/%s" . ) | absURL }}">
|
||||
{{- /* Replace hyphen with non-breaking hyphen */ -}}
|
||||
{{- replace (urlize .) "-" "‑" | safeHTML -}}
|
||||
</a>
|
||||
{{- end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
{{ if .page.Params.cover }}
|
||||
<!--
|
||||
Only lazy-load images below-the-fold. For post lists, start loading
|
||||
covers from the third post and onwards.
|
||||
-->
|
||||
{{ $lazy := ge .pageIndex 2 }}
|
||||
{{ partial "image.html" (dict "src" .page.Params.cover.src "alt" .page.Params.cover.alt "caption" .page.Params.cover.caption "page" .page "lazy" $lazy) }}
|
||||
{{ end }}
|
||||
</div>
|
@@ -0,0 +1,30 @@
|
||||
<div class="sidebar">
|
||||
{{ if .Params.toc }}
|
||||
{{ with .TableOfContents }}
|
||||
<aside class="toc">
|
||||
<nav>
|
||||
<p class="sidebar__heading">Table Of Contents</p>
|
||||
{{ . }}
|
||||
</nav>
|
||||
</aside>
|
||||
<hr />
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{ $cv := index $.Site.Data.json_resume $.Site.Language.Lang }}
|
||||
{{ if $cv.basics }}
|
||||
<aside class="bio">
|
||||
{{ partial "json-resume/basics.html" . }}
|
||||
|
||||
{{ if $.Site.Params.tagCloud.enable }}
|
||||
<hr />
|
||||
{{ end }}
|
||||
</aside>
|
||||
{{ end }}
|
||||
|
||||
{{ if $.Site.Params.tagCloud.enable }}
|
||||
<aside>
|
||||
{{ partial "tag-cloud.html" . }}
|
||||
</aside>
|
||||
{{ end }}
|
||||
</div>
|
@@ -0,0 +1,20 @@
|
||||
{{ $url := .Permalink }}
|
||||
{{ $title := .Title }}
|
||||
{{ with $.Site.Params.socialShare }}
|
||||
<div class="social-share">
|
||||
<strong class="social-share__heading">Share this post: </strong>
|
||||
{{ range . }}
|
||||
{{ $href := .formatString }}
|
||||
{{ $href := replace $href "{url}" (urlquery $url) }}
|
||||
{{ $href := replace $href "{title}" (urlquery $title) }}
|
||||
<a
|
||||
class="social-share__item"
|
||||
href="{{ $href | safeURL }}"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
{{ partial (printf "icons/%s" .iconSuite) .iconName }}
|
||||
</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
@@ -0,0 +1,32 @@
|
||||
<!--
|
||||
Original work by Artem Sidorenko: https://www.sidorenko.io/post/2017/07/nice-tagcloud-with-hugo/
|
||||
Creative Commons Attribution 4.0 International License (https://creativecommons.org/licenses/by/4.0/)
|
||||
-->
|
||||
|
||||
{{ with $.Site.Taxonomies.tags }}
|
||||
{{ $fontUnit := "rem" }}
|
||||
{{ $minFontSize := $.Site.Params.tagCloud.minFontSizeRem | default 0.8 }}
|
||||
{{ $maxFontSize := $.Site.Params.tagCloud.maxFontSizeRem | default 2.0 }}
|
||||
{{ $fontSizeSpread := sub $maxFontSize $minFontSize }}
|
||||
{{ $min := len (index .ByCount.Reverse 0).Pages }}
|
||||
{{ $max := add (len (index .ByCount 0).Pages) 1 }}
|
||||
|
||||
|
||||
<div class="tag-cloud">
|
||||
{{ range $tagName, $weightedPages := . }}
|
||||
{{ $count := len $weightedPages.Pages }}
|
||||
{{ $weight := div (sub (math.Log $count) (math.Log $min)) (sub (math.Log $max) (math.Log $min)) }}
|
||||
{{ $fontSize := (add $minFontSize (mul $fontSizeSpread $weight) ) }}
|
||||
<a
|
||||
href="{{ "/tags/" | relLangURL }}{{ $tagName | urlize }}"
|
||||
style="font-size:{{ $fontSize }}{{ $fontUnit }}"
|
||||
{{ if eq $.Page.Params.title $tagName -}}
|
||||
class="tag-cloud__tag tag-cloud__tag--active"
|
||||
{{ else -}}
|
||||
class="tag-cloud__tag"
|
||||
{{ end -}}
|
||||
>{{ $tagName }}</a
|
||||
>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|