From 66ca3fca7596048ff7511a8361912ba2434c2b72 Mon Sep 17 00:00:00 2001 From: George Cushen Date: Sat, 30 Sep 2017 16:26:19 +0100 Subject: [PATCH] Add theme system - Add `color_theme` option to config - Add `font` option to config - Add 3 themes - Add 2 font styles - Add documentation to Getting Started post --- data/fonts/classic.toml | 14 ++ data/fonts/default.toml | 14 ++ data/themes/default.toml | 20 +++ data/themes/forest.toml | 20 +++ data/themes/ocean.toml | 20 +++ exampleSite/config.toml | 13 ++ exampleSite/content/post/getting-started.md | 27 +++- layouts/index.css | 9 ++ .../partials/css/academic.css | 135 ++++++++++++------ layouts/partials/css/parse_theme.css | 32 +++++ layouts/partials/header.html | 8 +- 11 files changed, 261 insertions(+), 51 deletions(-) create mode 100644 data/fonts/classic.toml create mode 100644 data/fonts/default.toml create mode 100644 data/themes/default.toml create mode 100644 data/themes/forest.toml create mode 100644 data/themes/ocean.toml create mode 100644 layouts/index.css rename static/css/hugo-academic.css => layouts/partials/css/academic.css (86%) create mode 100644 layouts/partials/css/parse_theme.css diff --git a/data/fonts/classic.toml b/data/fonts/classic.toml new file mode 100644 index 00000000..4b9e568c --- /dev/null +++ b/data/fonts/classic.toml @@ -0,0 +1,14 @@ +# Font style metadata +name = "Classic" + +# Optional Google font URL +google_fonts = "Playfair Display:400,700|Fauna One" + +# Font families +heading_font = "Playfair Display" +body_font = "Fauna One" +mono_font = "Roboto Mono" + +# Font size +font_size = "20" +font_size_small = "16" diff --git a/data/fonts/default.toml b/data/fonts/default.toml new file mode 100644 index 00000000..9ca2bc2a --- /dev/null +++ b/data/fonts/default.toml @@ -0,0 +1,14 @@ +# Font style metadata +name = "Default" + +# Optional Google font URL +google_fonts = "Montserrat:400,700|Roboto:400,400italic,700|Roboto+Mono" + +# Font families +heading_font = "Montserrat" +body_font = "Roboto" +mono_font = "Roboto Mono" + +# Font size +font_size = "20" +font_size_small = "16" diff --git a/data/themes/default.toml b/data/themes/default.toml new file mode 100644 index 00000000..738be90a --- /dev/null +++ b/data/themes/default.toml @@ -0,0 +1,20 @@ +# Theme metadata +name = "Default" + +# Is theme light or dark? +light = true + +# Primary +primary = "#0095eb" +primary_light = "#6ec6ff" +primary_dark = "#0069c0" + +# Menu +menu_primary = "#fff" +menu_text = "#34495e" +menu_text_active = "#0095eb" +menu_title = "#2b2b2b" + +# Home sections +home_section_odd = "rgb(255, 255, 255)" +home_section_even = "rgb(247, 247, 247)" diff --git a/data/themes/forest.toml b/data/themes/forest.toml new file mode 100644 index 00000000..a1559333 --- /dev/null +++ b/data/themes/forest.toml @@ -0,0 +1,20 @@ +# Theme metadata +name = "Forest" + +# Is theme light or dark? +light = true + +# Primary +primary = "#4caf50" +primary_light = "#80e27e" +primary_dark = "#087f23" + +# Menu +menu_primary = "#4caf50" +menu_text = "#fff" +menu_text_active = "#1b5e20" +menu_title = "#fff" + +# Home sections +home_section_odd = "rgb(255, 255, 255)" +home_section_even = "rgb(247, 247, 247)" diff --git a/data/themes/ocean.toml b/data/themes/ocean.toml new file mode 100644 index 00000000..3aa4e129 --- /dev/null +++ b/data/themes/ocean.toml @@ -0,0 +1,20 @@ +# Theme metadata +name = "Ocean" + +# Is theme light or dark? +light = true + +# Primary +primary = "#3f51b5" +primary_light = "#757de8" +primary_dark = "#002984" + +# Menu +menu_primary = "#3f51b5" # 500 +menu_text = "#fff" +menu_text_active = "#8c9eff" # A100 +menu_title = "#fff" + +# Home sections +home_section_odd = "rgb(255, 255, 255)" +home_section_even = "rgb(247, 247, 247)" diff --git a/exampleSite/config.toml b/exampleSite/config.toml index 241b2785..8213d4b5 100644 --- a/exampleSite/config.toml +++ b/exampleSite/config.toml @@ -5,6 +5,7 @@ theme = "academic" enableEmoji = true footnotereturnlinkcontents = "^" ignoreFiles = ["\\.Rmd$", "\\.Rmarkdown$", "_files$", "_cache$"] +paginate = 10 # Enable comments by entering your Disqus shortname disqusShortname = "" @@ -16,10 +17,22 @@ googleAnalytics = "" defaultContentLanguage = "en" defaultContentLanguageInSubdir = false +[outputs] + home = [ "HTML", "CSS" ] + [blackfriday] hrefTargetBlank = true [params] + # Color theme. + # Choose from `default`, `ocean`, or `forest`. + color_theme = "default" + + # Font style. + # Choose from `default` or `classic`. + font = "default" + + # Your details. name = "Lena Smith" role = "Professor of Artificial Intelligence" organization = "Stanford University" diff --git a/exampleSite/content/post/getting-started.md b/exampleSite/content/post/getting-started.md index a3a61f0d..d7ef29b8 100644 --- a/exampleSite/content/post/getting-started.md +++ b/exampleSite/content/post/getting-started.md @@ -90,6 +90,21 @@ Refer to our guide on [managing content]({{< ref "post/managing-content.md" >}}) [How to remove unused widgets and content pages]({{< ref "post/managing-content.md#removing-content" >}}). +### Themes + +The following color themes are available and can be set by the `color_theme` option in `config.toml`: + +- default (light blue) +- ocean (deep blue) +- forest (green) + +### Font + +The following font styles are available and can be set by the `font` option in `config.toml`: + +- default (modern) +- classic + ### Customization & updating Continue reading below for advanced customization tips and instructions for keeping the framework up-to-date with any improvements that become available. @@ -109,12 +124,6 @@ To create a dropdown sub-menu, add `identifier = "something"` to the parent item Save your main icon and mobile icon as square PNG images named `icon.png` and `apple-touch-icon.png`, respectively. Place them in your root `static/img/` folder. -### Theme color (CSS) - -You can link custom CSS assets (relative to your root `static/css`) from your `config.toml` using `custom_css = ["custom.css"]`. - -For example, lets make a green theme. First, define `custom_css = ["green.css"]` in `config.toml`. Then we can download the example [green theme](https://gist.github.com/gcushen/d5525a4506b9ccf83f2bce592a895495) and save it as `static/css/green.css`, relative to your website root (i.e. **not** in the `themes` directory). - ### Analytics To enable [Google Analytics](http://www.google.com/analytics), add your tracking code in `config.toml` similarly to `googleAnalytics = "UA-12345678-9"`. @@ -148,6 +157,12 @@ For further details on Hugo's internationalization and multilingual features, re Where `:slug` defaults to the filename of the post, excluding the file extension. However, slug may be overridden on a per post basis if desired, simply by setting `slug = "my-short-post-title"` in your post preamble. +### Advanced style customization (CSS) + +For advanced customization of the style, you can link custom CSS assets (relative to your root `static/css`) from your `config.toml` using `custom_css = ["custom.css"]`. + +For example, let's override some of Academic's default styles. First, define `custom_css = ["override.css"]` in `config.toml`. Then we can create the file `static/css/override.css`, relative to your website root (i.e. **not** in the `themes` directory). Add your custom CSS to this file. + ## Updating diff --git a/layouts/index.css b/layouts/index.css new file mode 100644 index 00000000..d1ae6b73 --- /dev/null +++ b/layouts/index.css @@ -0,0 +1,9 @@ +{{- $scr := .Scratch -}} +{{- $scr.Set "site" $.Site -}} + +{{- partial "css/parse_theme.css" . -}} + +{{- $scr.Set "css" (partial "css/academic.css" $scr) -}} + +{{/* Return parsed CSS. */}} +{{- $scr.Get "css" -}} diff --git a/static/css/hugo-academic.css b/layouts/partials/css/academic.css similarity index 86% rename from static/css/hugo-academic.css rename to layouts/partials/css/academic.css index b9b57100..4dbaa583 100644 --- a/static/css/hugo-academic.css +++ b/layouts/partials/css/academic.css @@ -21,14 +21,14 @@ } html { - font-family: 'Merriweather', serif; - font-size: 16px; + font-family: '{{ .Get "body_font" }}', sans-serif; + font-size: {{ .Get "font_size_small" }}px; color: rgba(0,0,0,0.8); line-height: 1.65; } @media screen and (min-width: 58em) { html { - font-size: 20px; + font-size: {{ .Get "font_size" }}px; } } @@ -61,7 +61,7 @@ ul, ol, dl { /* Navigation bar text */ .navbar-default { - font-family: 'Lato', sans-serif; + font-family: '{{ .Get "body_font" }}', sans-serif; font-weight: 400; line-height: 1.25; text-rendering: optimizeLegibility; @@ -69,7 +69,7 @@ ul, ol, dl { /* Headings */ h1, h2, h3, h4, h5, h6 { - font-family: 'Lato', sans-serif; + font-family: '{{ .Get "heading_font" }}', sans-serif; font-weight: 400; margin-bottom: .5rem; line-height: 1.25; @@ -96,14 +96,14 @@ h4, h5, h6 { a, h3.article-title a:hover { - color: #0095eb; + color: {{ .Get "primary" }}; text-decoration: none; transition: color 0.6s ease; } a:hover, a:focus { - color: #005181; + color: {{ .Get "primary" }}; } img, @@ -130,7 +130,7 @@ figcaption { line-height: 1.25; font-size: 1rem; margin-bottom: 1.65rem; - font-family: 'Lato', sans-serif; + font-family: '{{ .Get "heading_font" }}', sans-serif; counter-increment: captions; } @@ -143,7 +143,7 @@ figcaption h4 { pre, code { - font-family: 'Roboto Mono', 'Courier New', 'Courier', monospace; + font-family: '{{ .Get "mono_font" }}', monospace; } pre { @@ -210,7 +210,7 @@ blockquote p:last-child { } .home-section { - background-color: rgb(255, 255, 255); + background-color: {{ .Get "home_section_odd" }}; padding: 110px 0 110px 0; animation: intro 0.3s both; animation-delay: 0.15s; @@ -221,7 +221,7 @@ blockquote p:last-child { } .home-section:nth-of-type(even) { - background-color: rgb(247, 247, 247); + background-color: {{ .Get "home_section_even" }}; } @media screen and (max-width: 768px) { @@ -238,7 +238,6 @@ blockquote p:last-child { } .section-heading p { - font-family: 'Lato', sans-serif; font-weight: 400; font-size: 1.1rem; color: #b2b2b2; @@ -261,8 +260,6 @@ blockquote p:last-child { margin: 0 auto; border-radius: 50%; background-size: cover; - -webkit-background-size: cover; - -moz-background-size: cover; } #profile .portrait-title h2 { @@ -273,13 +270,13 @@ blockquote p:last-child { } #profile .portrait-title h3 { - font-size: 1.13em; + font-size: 1rem; font-weight: 300; - color: #AAAAAA; + color: rgba(0,0,0, 0.54); margin: 0px 0 10px 0; } -#profile ul.social-icon { +#profile ul.network-icon { display: inline-flex; flex-direction: row; flex-wrap: wrap; @@ -288,15 +285,15 @@ blockquote p:last-child { margin-top: 30px; } -#profile .social-icon li { +#profile .network-icon li { margin-right: 10px; } -#profile .social-icon li:last-of-type { +#profile .network-icon li:last-of-type { margin-right: 0; } -#profile .social-icon li:hover { +#profile .network-icon li:hover { transform: scale(1.2) } @@ -452,7 +449,7 @@ article { } .article-metadata a:hover { - color: #0095eb; + color: {{ .Get "primary" }}; } .article-list-item { @@ -503,7 +500,7 @@ article { **************************************************/ .pub-icon { - color: #03396c; + color: rgba(0, 0, 0, 0.54); font-size: 0.81em; padding-top: 6px; } @@ -758,16 +755,16 @@ footer a#back_to_top i { **************************************************/ .btn-primary { - border-color: #0095eb; - background: #0095eb; + border-color: {{ .Get "primary" }} !important; + background: {{ .Get "primary" }} !important; } .btn-primary:hover, -.btn-primary:focus, .btn-primary:active, .btn-primary.active, +.btn-primary:visited, .open > .dropdown-toggle.btn-primary { - background: #0095eb; + background: {{ .Get "primary" }} !important; } /************************************************* @@ -790,12 +787,12 @@ footer a#back_to_top i { .btn-toolbar .btn.btn-primary:hover, .btn-toolbar .btn.btn-primary:focus { - background-color: rgba(0,149,235,0.6); + background-color: {{ .Get "primary_dark" }} !important; } .btn-toolbar .btn.btn-primary:active, .btn-toolbar .btn.btn-primary.active { - background-color: rgba(0,89,175,1); + background-color: {{ .Get "primary_light" }} !important; } /************************************************* @@ -803,14 +800,22 @@ footer a#back_to_top i { **************************************************/ .btn-outline { - background-color: transparent; + background-color: transparent !important; color: inherit; transition: all .5s; } .btn-primary.btn-outline { - color: #0095eb; - border-color: #0095eb; + color: {{ .Get "primary" }} !important; + border-color: {{ .Get "primary" }} !important; +} + +.btn-primary.btn-outline:focus { + color: {{ .Get "primary" }} !important; +} + +.btn-primary.btn-outline:active { + color: #fff !important; } .btn-success.btn-outline { @@ -834,7 +839,7 @@ footer a#back_to_top i { .btn-info.btn-outline:hover, .btn-warning.btn-outline:hover, .btn-danger.btn-outline:hover { - color: #fff; + color: #fff !important; } /************************************************* @@ -846,12 +851,21 @@ footer a#back_to_top i { } .navbar-default { - background: #fff; + background: {{ .Get "menu_primary" }}; box-shadow: 0 0.125rem 0.25rem 0 rgba(0,0,0,.11) } +.navbar-default .navbar-toggle { + border-color: transparent; +} + +.navbar-default .navbar-toggle:focus, +.navbar-default .navbar-toggle:hover { + background-color: transparent; +} + nav#navbar-main li { - font-size: 16px; + font-size: {{ .Get "font_size_small" }}px; } .navbar-default .navbar-nav>li>a, @@ -860,14 +874,20 @@ nav#navbar-main li { white-space: nowrap; -webkit-transition: 0.2s ease; transition: 0.2s ease; - color: #34495e; + color: {{ .Get "menu_text" }}; font-weight: 600; } +.navbar-default .navbar-nav>li>a:focus, +.navbar-default .navbar-nav>li>a:hover { + color: {{ .Get "menu_text_active" }}; + background-color: transparent; +} + .navbar-default .navbar-nav>.active>a, .navbar-default .navbar-nav>.active>a:focus, .navbar-default .navbar-nav>.active>a:hover { - color: #0095eb; + color: {{ .Get "menu_text_active" }}; font-weight: 700; background-color: transparent !important; /* Override Bootstrap. */ } @@ -880,30 +900,59 @@ nav#navbar-main li { padding-bottom: 10px; } +.navbar-default .navbar-toggle .icon-bar { + background-color: {{ .Get "menu_text" }} !important; +} + +.dropdown-menu { + background-color: {{ .Get "menu_primary" }} !important; +} + .dropdown-menu > li > a { display: block; padding: 3px 20px; clear: both; font-weight: 400; line-height: 1.42857143; - color: #34495e; + color: {{ .Get "menu_text" }}; white-space: nowrap; } +.dropdown-menu>li>a:focus, +.dropdown-menu>li>a:hover { + color: {{ .Get "menu_text_active" }}; + text-decoration: none; + background-color: {{ .Get "menu_primary" }}; +} + .dropdown-menu > .active > a, .dropdown-menu > .active > a:focus, .dropdown-menu > .active > a:hover { - color: #fff; + color: {{ .Get "menu_primary" }}; text-decoration: none; - background-color: #0095eb; + background-color: {{ .Get "menu_text_active" }}; outline: 0; } +.navbar-default .navbar-nav>.open>a, +.navbar-default .navbar-nav>.open>a:focus, +.navbar-default .navbar-nav>.open>a:hover, +.navbar-default .navbar-nav>.open>a:visited { + color: {{ .Get "menu_text" }} !important; + background-color: {{ .Get "menu_primary" }} !important; +} + .navbar-default .navbar-brand { text-transform: uppercase; font-weight: bold; font-size: 1.2em; - color: #2b2b2b; + color: {{ .Get "menu_title" }}; +} + +.navbar-default .navbar-brand:focus, +.navbar-default .navbar-brand:hover { + color: {{ .Get "menu_title" }}; + background-color: transparent; } @media screen and (max-width: 1200px) { @@ -963,7 +1012,7 @@ nav#navbar-main li { clear: both; font-weight: 400; line-height: 1.42857143; - color: #34495e; + color: {{ .Get "menu_text" }}; white-space: nowrap; } @@ -980,7 +1029,7 @@ nav#navbar-main li { .navbar-default .navbar-nav .open .dropdown-menu > li > a { padding: 5px 15px 5px 25px; line-height: 20px; - color: #34495e; + color: {{ .Get "menu_text" }}; } .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus, @@ -992,7 +1041,7 @@ nav#navbar-main li { .navbar-default .navbar-nav .open .dropdown-menu > .active > a, .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus, .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover { - color: #0095eb; + color: {{ .Get "menu_text_active" }}; background-color: transparent; } diff --git a/layouts/partials/css/parse_theme.css b/layouts/partials/css/parse_theme.css new file mode 100644 index 00000000..8288dfdd --- /dev/null +++ b/layouts/partials/css/parse_theme.css @@ -0,0 +1,32 @@ +{{- $scr := .Scratch -}} +{{- $site := $scr.Get "site" -}} + +{{/* Attempt to load font style specified by user. */}} +{{- $font_index := .Site.Params.font | default "default" -}} +{{ if isset .Site.Data.themes $font_index }} + {{- $font := index .Site.Data.fonts $font_index -}} + {{- $scr.Set "google_fonts" $font.google_fonts -}} + {{- $scr.Set "body_font" $font.body_font -}} + {{- $scr.Set "heading_font" $font.heading_font -}} + {{- $scr.Set "mono_font" $font.mono_font -}} + {{- $scr.Set "font_size" $font.font_size -}} + {{- $scr.Set "font_size_small" $font.font_size_small -}} +{{ end }} + +{{/* Attempt to load color theme specified by user. */}} +{{- $theme_index := .Site.Params.color_theme | default "default" -}} +{{ if isset .Site.Data.themes $theme_index }} + {{ $theme := index .Site.Data.themes $theme_index }} + + {{- $scr.Set "primary" $theme.primary -}} + {{- $scr.Set "primary_light" $theme.primary_light -}} + {{- $scr.Set "primary_dark" $theme.primary_dark -}} + + {{- $scr.Set "menu_primary" $theme.menu_primary -}} + {{- $scr.Set "menu_text" $theme.menu_text -}} + {{- $scr.Set "menu_text_active" $theme.menu_text_active -}} + {{- $scr.Set "menu_title" $theme.menu_title -}} + + {{- $scr.Set "home_section_odd" $theme.home_section_odd -}} + {{- $scr.Set "home_section_even" $theme.home_section_even -}} +{{ end }} diff --git a/layouts/partials/header.html b/layouts/partials/header.html index 3eaa3c51..8be5bd35 100644 --- a/layouts/partials/header.html +++ b/layouts/partials/header.html @@ -36,8 +36,12 @@ {{ end }} {{/* We cannot use SRI with Google Fonts because the CSS is dynamically generated according to the user agent */}} - - + {{- partial "css/parse_theme.css" . -}} + {{- $scr := .Scratch -}} + {{ with ($scr.Get "google_fonts") }} + + {{ end }} + {{ range .Site.Params.custom_css }} {{ end }}