diff --git a/_data/navTop.js b/_data/navTop.js index 318c66da..7eb4e060 100644 --- a/_data/navTop.js +++ b/_data/navTop.js @@ -11,12 +11,4 @@ module.exports = [ name: 'Sponsor us', url: 'https://opencollective.com/timber', }, - { - image: { - alt: 'Star on Github', - src: '/build/img/github.png', - style: 'width: 29px; height: 29px; border: 0', - }, - url: 'https://github.com/timber/timber', - }, ]; diff --git a/_includes/header.njk b/_includes/header.njk index a7828980..7ef125be 100644 --- a/_includes/header.njk +++ b/_includes/header.njk @@ -1,12 +1,17 @@
- Timber Logo + + Timber
@@ -31,9 +36,17 @@ {% endfor %} +
  • + + Star on Github + + +
  • + {% include 'theme-switcher.njk' %} + diff --git a/assets/img/timber-logo.svg b/assets/img/timber-logo.svg deleted file mode 100644 index 8c6157b9..00000000 --- a/assets/img/timber-logo.svg +++ /dev/null @@ -1 +0,0 @@ -Logo Tiny White \ No newline at end of file diff --git a/assets/js/app.js b/assets/js/app.js index 95eef45a..95c6abcc 100644 --- a/assets/js/app.js +++ b/assets/js/app.js @@ -1,5 +1,6 @@ import { slideup } from './navigation'; import Turbolinks from 'turbolinks'; +import "./themeSwitcher"; Turbolinks.start(); diff --git a/assets/js/themeSwitcher.js b/assets/js/themeSwitcher.js new file mode 100644 index 00000000..019235ab --- /dev/null +++ b/assets/js/themeSwitcher.js @@ -0,0 +1,20 @@ +window.switchTheme = () => { + const isDark = window.localStorage.getItem('theme') === 'dark'; + document.documentElement.setAttribute('data-theme', isDark ? 'light' : 'dark'); + + localStorage.setItem("theme", document.documentElement.getAttribute('data-theme')); +} + +document.addEventListener('DOMContentLoaded', () => { + const theme = (() => { + if (typeof localStorage !== 'undefined' && localStorage.getItem('theme')) { + return localStorage.getItem('theme'); + } + if (window.matchMedia('(prefers-color-scheme: dark)').matches) { + return 'dark'; + } + return 'light'; + })(); + document.documentElement.setAttribute('data-theme', theme); + window.localStorage.setItem('theme', theme); +}); diff --git a/assets/sass/_base.scss b/assets/sass/_base.scss index 5df7498d..c0d25083 100644 --- a/assets/sass/_base.scss +++ b/assets/sass/_base.scss @@ -1,3 +1,5 @@ + + html { -webkit-tap-highlight-color: rgba(0,0,0,0); box-sizing: border-box; @@ -15,20 +17,87 @@ html { } body { + --text-color: #{$white}; + --bg-color: #{$main-bg}; + --version-note: #222; + --link-color: #{$white}; + --link-border-color: #{$green-light}; + --header-bg-color: #{$black}; + --header-logo-text-color: #{$white}; + --header-logo-shape-color: #{$green-light}; + --sidebar-link-active-color: #{$green-light}; + --sidebar-border-color: #{$grey-dark}; + --sidebar-version-link-color: #{$white}; + --sidebar-version-link-hover-color: #{$black}; + --sidebar-version-link-hover-background-color: #{$white}; + --sidebar-version-link-border-color: #{$white}; + --sidebar-version-link-border-hover-color: #{$black}; + --theme-switcher-color: #{$white}; + --theme-switcher-indicator--dark-display: none; + --theme-switcher-indicator--light-display: block; + --version-note-link-color: #{$white}; + --version-note-link-border-color: #{$green-light}; + --toc-link-hover-color: #{$green-light}; + --code-color: #{$green-light}; + --code-background-color: #{$grey-dark}; + --code-link-border-color: #{$green-light}; + --table-code-text-color: #{$green-light}; + --headings-code-color: #{$green-light}; + --direct-link-hover-color: #{$green-light}; + --nav-mobile-toggle-color: #{$green-light}; + --pre-code-color: #{$green-light}; + + color: var(--text-color); + background-color: var(--bg-color); display: flex; min-height: 100vh; - flex-direction: column; - - color: $text-color; - padding: 0; - margin: 0; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - background-color: $main-bg; - height: 100%; + flex-direction: column; + padding: 0; + margin: 0; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + height: 100%; line-height: 1.6; - -webkit-text-size-adjust: none; /* Never autoresize text */ - @include font-text; + -webkit-text-size-adjust: none; /* Never autoresize text */ + @include font-text; + + /* + All colors that are applied to ligth theme should be defined here, + and then use these custom properties in each components as needed. + */ + html[data-theme="light"] & { + --text-color: #{$black}; + --link-color: #{$black}; + --link-border-color: #{$green}; + --toc-text-decoration: underline; + --text-color-inverse: #{$white}; + --bg-color: #{$white}; + --version-note: #{$green}; + --header-bg-color: #{$white}; + --header-logo-text-color: #{$black}; + --header-logo-shape-color: #{$black}; + --sidebar-link-active-color: #{$green}; + --sidebar-border-color: #{$border-color}; + --sidebar-version-link-color: #{$black}; + --sidebar-version-link-hover-color: #{$white}; + --sidebar-version-link-hover-background-color: #{$green}; + --sidebar-version-link-border-color: #{$black}; + --sidebar-version-link-hover-border-color: #{$green}; + --theme-switcher-color: #{$black}; + --theme-switcher-indicator--dark-display: block; + --theme-switcher-indicator--light-display: none; + --version-note-link-color: #{$white}; + --version-note-link-border-color: #{$white}; + --toc-link-hover-color: #{$green}; + --code-color: #007f4b; + --code-background-color: #{$grey-lighter}; + --code-link-border-color: #{$green}; + --table-code-text-color: #{$green}; + --headings-code-color: #{$green}; + --direct-link-hover-color: #{$green}; + --nav-mobile-toggle-color: #{$black}; + --pre-code-color: #{$white}; + } } .wrapper { diff --git a/assets/sass/_code.scss b/assets/sass/_code.scss index c020d6be..d6b0985d 100644 --- a/assets/sass/_code.scss +++ b/assets/sass/_code.scss @@ -1,36 +1,40 @@ code { - color: $green-light; + color: var(--code-color); + background-color: var(--code-background-color); white-space: pre-wrap; text-transform: none; font-weight: $font-weight-normal; + padding: 3px 5px; + border-radius: 2px; @include font-code; } -p > code, -li > code, +pre:not([class*="language-"]) code { + color: var(--pre-code-color); +} + a > code { - padding: 3px 5px; - background: $grey-dark; - border-radius: 2px; + border-bottom: 1px solid var(--code-link-border-color); + + &:hover { + // Increase border width so it has a clear hover style. + border-width: 2px; + } } -p > code, -li > code { - margin: 0 2px; +td code { + background-color: transparent; } h1, h2, h3, h4, h5, h6 { code { font-size: inherit; + // Keep color same as heading, although make it italic to stand out a bit. + color: var(--headings-code-color); + background-color: transparent; } } -a > code { - color: $green-light; - @include font-code; - border-bottom: 1px solid $green-light; -} - a:has(> code){ margin: 0 2px; } @@ -38,13 +42,13 @@ a:has(> code){ .method-name, .method-name a, .property-name { - color: $green-light; + color: var(--code-link-border-color); @include font-code; } .method-type, .method-type code, -.property-type, +.property-type, .property-type code{ color: $purple; @include font-code; @@ -52,6 +56,7 @@ a:has(> code){ table code { word-break: normal; + color: var(--table-code-text-color); } pre > code { @@ -63,11 +68,8 @@ pre { background-color: $code-bg; color: $text-color; border-radius: 4px; - - padding: 2em $gutter-width/2; - margin: 5px 0 20px $gutter-width/-2; - width: calc(100% + #{$gutter-width/2}); - + padding: 1em; + margin-block: 5px 20px; clear: right; & > p { @@ -75,4 +77,4 @@ pre { } @include font-code; -} +} \ No newline at end of file diff --git a/assets/sass/_header.scss b/assets/sass/_header.scss index e1612e4e..866fcd4c 100644 --- a/assets/sass/_header.scss +++ b/assets/sass/_header.scss @@ -1,14 +1,13 @@ .header { + background-color: var(--header-bg-color); + display: flex; flex-wrap: wrap; align-items: center; - position: relative; z-index: 1000; - width: 100%; - background-color: $black; - box-shadow: 0 3px 8px rgba(0, 0, 0, 0.15); - + width: 100%; + box-shadow: 0 3px 8px rgba(0, 0, 0, 0.15); padding: 15px 1rem; @media (max-width: 767px) { @@ -25,27 +24,31 @@ } } - @media (min-width: $header-breakpoint) { + @media (min-width: $header-breakpoint) { padding-left: 4em; padding-right: 4em; position: fixed; flex-wrap: nowrap; justify-content: space-between; } - + a { border-bottom: none; } - } .logo { - height: $header-height; + width: 105px; + height: 30px; - img { - position: relative; - } + .text { + fill: var(--header-logo-text-color); + } + + .shape { + fill: var(--header-logo-shape-color); + } } .navTop { @@ -53,45 +56,47 @@ flex-grow: 1; ul { - width: 100%; - - display: flex; - align-items: center; - list-style: none; - margin: 0; - padding: 0; - - & > * + * { - margin-left: 1em; - } + width: 100%; + display: flex; + align-items: center; + list-style: none; + margin: 0; + padding: 0; + + & > * + * { + margin-left: 1em; + } } li { vertical-align: middle; - &:last-child { - margin-left: auto; - } + &:last-child { + margin-left: auto; + } } a { - display: block; - font-size: 0.9em; - text-decoration: none; - color: $white; - font-weight: $font-weight-bold; - letter-spacing: .25px; - padding: 4px; - - - &:hover, &:focus { - color: $white; - text-decoration: underline; - - } - - img { display: block; - } + font-size: 0.9em; + text-decoration: none; + color: var(--link-color); + font-weight: $font-weight-bold; + letter-spacing: .25px; + padding: 4px; + + &:hover, &:focus { + color: inherit; + text-decoration: underline; + } + + img { + display: block; + } } } + +.nav-link { + width: 2.5rem; + height: 2.5rem; +} diff --git a/assets/sass/_headings.scss b/assets/sass/_headings.scss index 2e37c2c9..1bbb0fca 100644 --- a/assets/sass/_headings.scss +++ b/assets/sass/_headings.scss @@ -1,57 +1,55 @@ h1, h2, h3, h4, h5, h6 { - display: block; - padding: 0; - margin: 0; - width: 100%; + display: block; + padding: 0; + margin: 0; + width: 100%; align-items: center; } h2, h3, h4, h5, h6 { - color: $headings-color; - line-height: 1.2; + color: var(--text-color); + line-height: 1.2; } h1 { - font-size: 3.75em; - color: $white; - font-weight: $font-weight-normal; - line-height: 1.2em; + font-size: 3.75em; + font-weight: $font-weight-normal; + line-height: 1.2em; } h2 { - font-size: 2.25em; - font-weight: $font-weight-normal; - color: $headings-color; + font-size: 2.25em; + font-weight: $font-weight-normal; } .content h2 { - &:after { - content: ""; - display: block; - width: 100%; - margin-top: 0.25em; - height: 2px; - border-bottom: 2px solid $green; - } + &:after { + content: ""; + display: block; + width: 100%; + margin-top: 0.25em; + height: 2px; + border-bottom: 2px solid $green; + } } h3 { - font-size: 1.4rem; - font-weight: $font-weight-bold; + font-size: 1.4rem; + font-weight: $font-weight-bold; } h4, .heading-4, h6 { - font-size: 1.25rem; - font-weight: $font-weight-bold; + font-size: 1.25rem; + font-weight: $font-weight-bold; } h5 { - font-size: .875rem; - font-weight: $font-weight-bold; + font-size: .875rem; + font-weight: $font-weight-bold; } .heading-small { - font-size: 1.3em; - color: $white; + font-size: 1.3em; + color: $white; } diff --git a/assets/sass/_links.scss b/assets/sass/_links.scss index a2e12b13..65467e89 100644 --- a/assets/sass/_links.scss +++ b/assets/sass/_links.scss @@ -13,13 +13,13 @@ h1, h2, h3, h4, h5, h6, // General links styling a { - color: $white; + color: var(--link-color); text-decoration: none; - border-bottom: 1px solid $green-light; + border-bottom: 1px solid var(--link-border-color); &:hover, &:focus { - color: $link-hover-color; + color: inherit; text-decoration: none; } } @@ -29,7 +29,7 @@ a { visibility: hidden; &:hover, &:focus { - color: $green-light; + color: var(--direct-link-hover-color); text-decoration: none; } } diff --git a/assets/sass/_nav-main.scss b/assets/sass/_nav-main.scss index 8cae13f7..8a1c985a 100644 --- a/assets/sass/_nav-main.scss +++ b/assets/sass/_nav-main.scss @@ -16,7 +16,7 @@ } .navMain-title { - color: $white; + color: var(--text-color); font-size: 0.85em; letter-spacing: 0.1em; text-transform: uppercase; @@ -42,18 +42,19 @@ .navMain-link { display: block; text-decoration: none; - color: $white; + color: var(--link-color); border-bottom: none; &:hover, &:focus { - text-decoration: none; + // I believe for accessibilty consideration, we need to have underline. + text-decoration: underline; } &[aria-current] { font-weight: $font-weight-bold; padding-top: 0.2em; padding-bottom: 0.3em; - color: $green-light; + color: var(--sidebar-link-active-color); } } diff --git a/assets/sass/_nav-mobile.scss b/assets/sass/_nav-mobile.scss index ff018e0f..1861f486 100644 --- a/assets/sass/_nav-mobile.scss +++ b/assets/sass/_nav-mobile.scss @@ -16,7 +16,7 @@ margin: 0 0 0 1.25rem; padding: 0; background: transparent; - color: $green-light; + color: var(--nav-mobile-toggle-color); cursor: pointer; // [1] diff --git a/assets/sass/_prism.scss b/assets/sass/_prism.scss index be037c09..4fb29b2b 100644 --- a/assets/sass/_prism.scss +++ b/assets/sass/_prism.scss @@ -3,16 +3,25 @@ * @author Lukas Gächter */ +/* + * Added few hardcoded colors that I picked + * from Firefox Dev Tool when checking color contract ratio, + * since these colors only apply to code block for both light & dark themes, + * I didn't extract these colors as global variables. + */ + $prism-code: $text-color; $prism-light: $grey-light; -$prism-string: $green; // #690; -$prism-symbol: $red;// #905; $prism-keyword: $text-color; // #07a; $prism-function: $green-light;// #DD4A68; $prism-property: $text-color; -$prism-tag: $grey-light; $prism-attribute: $grey-light; $prism-attribute-value: $green; +$prism-delimiter-important: #a2a7f2; +$prism-string: #1dd288; +$prism-symbol: #FF7E81; +$prism-tag: #e6e6e6; +$prism-token-punctuation: #cacaca; code[class*="language-"], pre[class*="language-"] { @@ -76,7 +85,7 @@ pre[class*="language-"] { } code.language-html { - color: $grey; + color: $prism-tag; } .token.comment, @@ -87,7 +96,7 @@ code.language-html { } .token.punctuation { - color: #999; + color: $prism-token-punctuation; } .tag .ld, @@ -107,7 +116,7 @@ code.language-html { } .token .attr-name { - color: $prism-attribute; + color: $prism-tag; } .token.property { @@ -165,7 +174,7 @@ code.language-html { // PHP opening tags .token.delimiter.important { - color: $prism-light; + color: $prism-delimiter-important; font-weight: $font-weight-bold; } diff --git a/assets/sass/_sidebar.scss b/assets/sass/_sidebar.scss index 6137db37..e487c942 100644 --- a/assets/sass/_sidebar.scss +++ b/assets/sass/_sidebar.scss @@ -1,7 +1,7 @@ .sidebar { padding: $nav-padding $gutter-width/2 $gutter-width/2 $gutter-width/2; - background-color: $black; - border-right: solid 1px $grey-dark; + background-color: var(--bg-color); + border-right: solid 1px var(--sidebar-border-color); @media (min-width: $mobile-breakpoint) { position: sticky; @@ -10,7 +10,7 @@ overflow-y: scroll; } - @media (min-width: $header-breakpoint) { + @media (min-width: $header-breakpoint) { flex: 0 0 $sidebar-width; padding: 3em $nav-padding $nav-padding 4em; } @@ -38,17 +38,18 @@ } a { - color: $white; + color: var(--sidebar-version-link-color); display: block; - border: 1px solid $white; + border: 1px solid var(--sidebar-version-link-border-color); border-radius: 100px; padding: 8px 15px 9px; font-weight: $font-weight-bold; text-decoration: none; &.is-current, &:hover, &:focus { - background: $white; - color: $black; + color: var(--sidebar-version-link-hover-color); + background: var(--sidebar-version-link-hover-background-color); + border-color: var(--sidebar-version-link-hover-border-color); } } } diff --git a/assets/sass/_theme-switcher.scss b/assets/sass/_theme-switcher.scss new file mode 100644 index 00000000..cef6849e --- /dev/null +++ b/assets/sass/_theme-switcher.scss @@ -0,0 +1,36 @@ +.themeSwitcher { + color: var(--theme-switcher-color); + background-color: transparent; + border: none; + margin-left: 1rem; + cursor: pointer; + + &__indicator { + width: 2.5em; + height: 2.5em; + display: flex; + align-items: center; + justify-content: center; + + svg { + width: 100%; + height: 100%; + } + + &--light { + display: var(--theme-switcher-indicator--light-display); + } + + &--dark { + display: var(--theme-switcher-indicator--dark-display); + } + } + + @media (max-width: 767px) { + position: fixed; + top: 15px; + right: 4rem; + margin: 0; + color: var(--nav-mobile-toggle-color); // Match nav toggle color on mobile. + } +} diff --git a/assets/sass/_toc.scss b/assets/sass/_toc.scss index 9977e934..9a84b0ae 100644 --- a/assets/sass/_toc.scss +++ b/assets/sass/_toc.scss @@ -1,7 +1,6 @@ aside { padding: 1em 0 1.5em 0; margin-top: 3em; - border-bottom: solid 1px $grey-dark; .heading-small { color: $grey-light; @@ -39,11 +38,16 @@ aside, .toc { a { display: inline-block; - color: $white; + color: var(--link-color); text-decoration: none; margin-bottom: 0.3em; border-bottom: none; + &:hover, &:focus { + color: var(--toc-link-hover-color); + text-decoration: var(--toc-text-decoration, none); + } + &:before { display: inline-block; margin-right: 0.5em; @@ -54,11 +58,6 @@ aside, .toc { color: inherit; font-size: 0.9em; } - - &:hover, &:focus { - color: $green-light; - text-decoration: none; - } } } diff --git a/assets/sass/_variables.scss b/assets/sass/_variables.scss index b3f2d579..28d46353 100644 --- a/assets/sass/_variables.scss +++ b/assets/sass/_variables.scss @@ -13,6 +13,9 @@ $purple: #8E4CF8; $grey: #858585; $grey-light: #999; $grey-dark: #161616; +// This lighter grey works better for code background on light mode, +// not code block, just inline code element. +$grey-lighter: #efefef; $border-color: #dddddd; diff --git a/assets/sass/_version-note.scss b/assets/sass/_version-note.scss index 061c6697..81694db7 100644 --- a/assets/sass/_version-note.scss +++ b/assets/sass/_version-note.scss @@ -1,9 +1,15 @@ .version-note { - background-color: #222; + background-color: var(--version-note); + color: var(--text-color-inverse, var(--text-color)); padding: 1em; margin: 1em; border-radius: 4px; + a { + color: inherit; + border-color: var(--version-note-link-border-color); + } + p { margin: 0; } diff --git a/assets/sass/styles.scss b/assets/sass/styles.scss index 1bd83b0b..d8dde8d6 100644 --- a/assets/sass/styles.scss +++ b/assets/sass/styles.scss @@ -8,6 +8,7 @@ @import "content"; @import "code"; @import "header"; +@import "theme-switcher"; @import "headings"; @import "images"; @import "links";