Light theme for the documentation page (#931)

* light theme for docs, wip

* several switchers, fixes

* format

* fix

* sooner apllication of user's theme

* dark theme by default
This commit is contained in:
trean
2024-05-30 19:06:12 +02:00
committed by GitHub
parent e70771dde3
commit 6f49a1e761
24 changed files with 386 additions and 33 deletions
@@ -79,10 +79,12 @@ $theme-colors: (
'warning': $warning-50,
'danger': $error-50,
'light': $neutral-98,
'dark': $neutral-10,
'dark': $neutral-20,
);
$body-bg: $neutral-98;
$body-color: $neutral-30;
$headings-color: $neutral-20;
$link-color: $primary-50;
$link-hover-color: $primary-50;
$link-decoration: none;
@@ -1,7 +1,8 @@
@import 'base';
@import 'partials/theme-switch';
@import 'partials/docs-menu';
@import 'partials/documentation';
@import 'partials/documentation-article';
@import 'partials/table-contents';
@import 'partials/table-of-contents';
@import 'partials/feedback';
@import 'search/dark-theme';
@@ -49,6 +49,7 @@
button {
padding-left: $spacer * 2.8;
color: $neutral-70;
&:after {
content: '';
display: block;
@@ -95,10 +96,6 @@
display: block;
position: relative;
margin-bottom: $spacer * 0.5;
// hide native details marker
&::-webkit-details-marker {
display: none;
}
a {
display: flex;
@@ -191,4 +188,105 @@
}
}
}
[data-theme='light'] & {
border-color: $neutral-100;
background-color: $neutral-94;
&__button svg path {
stroke: $neutral-30;
}
&__header {
h2 {
color: $neutral-30;
}
&__content svg {
fill: $neutral-30;
}
}
&__input {
button {
color: $neutral-50;
&:after {
mask: url('/icons/outline/search-white.svg') no-repeat;
-webkit-mask: url('/icons/outline/search-white.svg') no-repeat;
background: $neutral-30;
}
}
}
&__links {
&-title {
color: $neutral-30;
}
&-group {
&-heading {
a {
color: $neutral-30;
&:hover {
color: $primary-50;
}
}
}
summary:after {
background-image: url("data:image/svg+xml,%3Csvg width='10' height='10' viewBox='0 0 10 10' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M3.16667 0.916341C3.10476 0.869913 3.03115 0.841641 2.95409 0.834692C2.87702 0.827742 2.79954 0.842391 2.73033 0.876997C2.66112 0.911602 2.60291 0.964797 2.56223 1.03062C2.52155 1.09644 2.5 1.17229 2.5 1.24967V8.74968C2.5 8.82706 2.52155 8.90291 2.56223 8.96873C2.60291 9.03455 2.66112 9.08775 2.73033 9.12235C2.79954 9.15696 2.87702 9.17161 2.95409 9.16466C3.03115 9.15771 3.10476 9.12944 3.16667 9.08301L8.16667 5.33301C8.21842 5.2942 8.26042 5.24387 8.28934 5.18601C8.31827 5.12816 8.33333 5.06436 8.33333 4.99967C8.33333 4.93499 8.31827 4.87119 8.28934 4.81334C8.26042 4.75548 8.21842 4.70515 8.16667 4.66634L3.16667 0.916341Z' fill='%2328324d'/%3E%3C/svg%3E");
}
&.active {
.docs-menu__links-group-heading > a {
color: $primary-50;
background: $neutral-90;
}
}
&[open=''] {
summary:after {
background-image: url("data:image/svg+xml,%3Csvg width='10' height='10' viewBox='0 0 10 10' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M4.66732 8.16667C4.70781 8.21588 4.75871 8.25552 4.81634 8.28273C4.87397 8.30995 4.93692 8.32406 5.00065 8.32406C5.06439 8.32406 5.12733 8.30995 5.18496 8.28273C5.2426 8.25552 5.29349 8.21588 5.33398 8.16667L9.08399 3.16667C9.13041 3.10476 9.15869 3.03115 9.16564 2.95409C9.17258 2.87702 9.15794 2.79954 9.12333 2.73033C9.08872 2.66112 9.03553 2.60291 8.96971 2.56223C8.90388 2.52155 8.82803 2.5 8.75065 2.5H1.25065C1.17327 2.5 1.09742 2.52155 1.0316 2.56223C0.965773 2.60291 0.912579 2.66112 0.877973 2.73033C0.843368 2.79954 0.828719 2.87702 0.835668 2.95409C0.842617 3.03115 0.87089 3.10476 0.917318 3.16667L4.66732 8.16667Z' fill='%2328324d'/%3E%3C/svg%3E");
}
}
svg path {
fill: $neutral-30;
}
}
&-submenu {
&-item {
a {
color: $neutral-30;
&:hover {
color: $primary-50;
}
}
&.active {
a {
color: $primary-50;
}
}
}
}
}
@include media-breakpoint-up(xl) {
background-color: $neutral-98;
&__links-group {
&.active {
.docs-menu__links-group-heading > a {
background-color: $neutral-94;
color: $neutral-30;
}
}
}
}
}
}
@@ -61,3 +61,31 @@
padding: 0 $spacer * 1.5;
}
}
[data-theme='light'] {
.documentation-article {
h1,
h2,
h3,
h4 {
color: $neutral-20;
}
p {
color: $neutral-30;
}
code:not([class]) {
color: $neutral-20;
background-color: #d9e2fe;
padding: 0.2em 0.4em;
border-radius: 0.4em;
}
.table-responsive {
.table {
@extend .table-light;
}
}
}
}
@@ -20,3 +20,10 @@
}
}
}
[data-theme='light'] {
.documentation {
background-color: $neutral-98;
color: $neutral-30;
}
}
@@ -56,4 +56,46 @@
display: block;
}
}
[data-theme='light'] & {
&__title {
color: $neutral-30;
}
&__question {
color: $neutral-30;
}
&__answer {
color: $neutral-30;
background-color: $neutral-90;
&_yes {
color: $success-10;
background-color: $success-90;
border: 1px solid $success-10;
&:hover {
background-color: $success-50;
color: $neutral-100;
}
}
&_no {
color: $error-10;
background-color: $error-90;
border: 1px solid $error-10;
&:hover {
background-color: $error-50;
color: $neutral-100;
}
}
}
&__response {
color: $neutral-30;
background: $neutral-90;
}
}
}
@@ -1,6 +1,6 @@
@use '../helpers/functions' as *;
.table-contents {
.table-of-contents {
background-color: $neutral-10;
margin-bottom: -1px;
@@ -32,6 +32,10 @@
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
&:hover {
color: $primary-50;
}
}
& > ul > li {
@@ -59,6 +63,9 @@
display: flex;
align-items: center;
gap: calc($spacer / 2);
&:hover {
text-decoration: underline;
}
}
svg {
@@ -74,4 +81,28 @@
display: block;
}
}
[data-theme='light'] & {
background-color: $neutral-98;
margin-bottom: $spacer * 2;
&__title {
color: $neutral-30;
}
a {
color: $neutral-30;
}
&__external-links {
border-top: 1px solid $neutral-90;
border-bottom: 1px solid $neutral-90;
}
&__link {
a {
color: $primary-50;
}
}
}
}
@@ -0,0 +1,34 @@
.theme-switch {
display: block;
width: $spacer * 1.25;
height: $spacer * 1.25;
border-radius: 50%;
background-color: transparent;
border: 0;
@mixin mask($url) {
mask: url($url);
mask-repeat: no-repeat;
mask-size: contain;
mask-position: center;
-webkit-mask: url($url);
-webkit-mask-repeat: no-repeat;
-webkit-mask-size: contain;
-webkit-mask-position: center;
}
&[data-theme-label='light'] {
@include mask('/icons/outline/sun.svg');
background-color: $neutral-60;
}
&[data-theme-label='dark'] {
@include mask('/icons/outline/moon.svg');
background-color: $neutral-60;
}
&[data-theme-label='auto'] {
@include mask('/icons/outline/half-circle.svg');
background-color: $neutral-60;
}
}
@@ -6,8 +6,8 @@
justify-content: center;
align-items: center;
gap: $spacer * 1.5;
border-bottom: 1px solid var(--Neutral-N20, #161e33);
background: var(--Neutral-N10, #090e1a);
border-bottom: 1px solid $neutral-20;
background: $neutral-10;
&__text {
color: $neutral-94;
@@ -1,6 +1,9 @@
.qdr-search__dialog {
[data-theme='dark'] .qdr-search__dialog {
background-color: $neutral-20;
color: $neutral-90;
h5 {
color: $neutral-90;
}
input {
background-color: $neutral-20;
color: $neutral-98;
@@ -2,4 +2,7 @@
.qdr-search {
z-index: 100;
.active h5 {
color: var(--bs-body-bg);
}
}
@@ -0,0 +1,14 @@
import ThemeSwitch from './theme-switch.js';
const themeSwitch = new ThemeSwitch();
document.addEventListener('DOMContentLoaded', () => {
themeSwitch.initSwitcher();
const sidebar = document.getElementById('sidebar');
const sidebarToggle = document.getElementById('sidebar-toggle');
sidebarToggle.addEventListener('click', () => {
sidebarToggle.classList.toggle('active');
sidebar.classList.toggle('active');
});
});
@@ -31,3 +31,7 @@ export function scrollIntoViewWithOffset(id, offset) {
window.addEventListener('scroll', scrollHandler);
});
}
export function isNodeList(list) {
return Object.prototype.isPrototypeOf.call(NodeList.prototype, list);
}
@@ -0,0 +1,64 @@
import { isNodeList } from './helpers';
/**
* ThemeSwitch
* @class
* @classdesc ThemeSwitch class to switch between dark, light and auto themes trough clicking on the switcher element , auto theme will change the theme based on the user's system preference
* @param {Object} options - ThemeSwitch options
* @param {HTMLElement|NodeList} options.switcher - Theme switcher element
* @param {Array} options.callbacks - Callbacks to run after theme switch
*/
class ThemeSwitch {
#userSwitcherEl = null;
constructor(options = { switcher: null, callbacks: [] }) {
this.#userSwitcherEl = options.switcher;
this.theme = localStorage.getItem('theme') || 'dark';
this.switcher = null;
this.callbacks = options.callbacks;
this.setTheme();
}
setTheme() {
let themeToApply;
if (this.theme === 'auto') {
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
themeToApply = 'dark';
} else {
themeToApply = 'light';
}
} else {
themeToApply = this.theme;
}
document.documentElement.setAttribute('data-theme', themeToApply);
if (!this.switcher) return;
if (isNodeList(this.switcher)) {
this.switcher.forEach((switcher) => {
switcher.setAttribute('data-theme-label', this.theme);
});
} else {
this.switcher.setAttribute('data-theme-label', this.theme);
}
localStorage.setItem('theme', this.theme);
}
toggleTheme() {
this.theme = this.theme === 'dark' ? 'light' : this.theme === 'light' ? 'auto' : 'dark';
this.setTheme();
this.callbacks.forEach((callback) => callback());
}
initSwitcher() {
this.switcher = this.#userSwitcherEl || document.querySelectorAll('.theme-switch');
if (isNodeList(this.switcher)) {
this.switcher.forEach((switcher) => {
switcher.addEventListener('click', () => this.toggleTheme());
});
} else {
this.switcher.addEventListener('click', () => this.toggleTheme());
}
this.setTheme();
}
}
export default ThemeSwitch;
@@ -42,7 +42,10 @@
</div>
</div>
</div>
<p class="core-features__subtitle mx-auto">{{ .Params.wall.intro_text }} <a class="link" target="_blank" href="{{ .Params.wall.url }}">{{ .Params.wall.url_text }}</a></p>
<p class="core-features__subtitle mx-auto">
{{ .Params.wall.intro_text }}
<a class="link" target="_blank" href="{{ .Params.wall.url }}">{{ .Params.wall.url_text }}</a>
</p>
</div>
</section>
{{ end }}
@@ -1,4 +1,4 @@
<section class="documentation">
<section class="documentation documentation_theme-light">
<div class="documentation__container">
<div class="row gx-4">
{{ partial "docs-menu" . }}
@@ -30,3 +30,8 @@
{{ $filterChartJs := resources.Get "/js/benchmarks/benchmarks_filtered_search.js" | minify | resources.Fingerprint "sha512" }}
<script src="{{ $filterChartJs.RelPermalink }}"></script>
{{ end }}
{{ if eq .Section "documentation" }}
{{ $documentationJs := resources.Get "/js/documentation.js" | js.Build | minify | resources.Fingerprint "sha512" }}
<script src="{{ $documentationJs.RelPermalink }}"></script>
{{ end }}
@@ -115,25 +115,16 @@
<script src="{{ $anchorJs.RelPermalink }}"></script>
{{ end }}
{{ if eq .Section "documentation" }}
<script>
document.getElementById('sidebar-toggle').addEventListener('click', () => {
document.getElementById('sidebar-toggle').classList.toggle('active');
document.getElementById('sidebar').classList.toggle('active');
});
</script>
{{ end }}
{{ if or (eq .Section "blog") (eq .Section "documentation") }}
<script>
document.addEventListener('keydown', function(event) {
if ((event.metaKey || event.ctrlKey) && event.key === 'k') {
<script>
document.addEventListener('keydown', function (event) {
if ((event.metaKey || event.ctrlKey) && event.key === 'k') {
event.preventDefault();
let searchButton = document.querySelector('[data-target="#searchModal"]');
if (searchButton) searchButton?.click();
}
});
</script>
}
});
</script>
{{ end }}
@@ -1,9 +1,18 @@
{{ $section := .Section }}
{{ with (.Site.GetPage "/headless/menu") }}
<div class="main-menu z-2">
<a href="/">
{{ partial "logo.html" . }}
</a>
<button type="button" class="main-menu__trigger">{{ partial "svg" "hamburger-menu-white.svg" }}</button>
<div class="d-flex justify-content-end align-items-center gap-4">
{{ if eq $section "documentation" }}
<div class="d-block d-xl-none">
{{ partial "theme-switch" . }}
</div>
{{ end }}
<button type="button" class="main-menu__trigger">{{ partial "svg" "hamburger-menu-white.svg" }}</button>
</div>
<ul class="main-menu__links">
{{ range .Params.menuItems }}
<li class="main-menu__item">
@@ -39,6 +48,9 @@
{{ end }}
</ul>
<div class="main-menu__buttons">
{{ if eq $section "documentation" }}
{{ partial "theme-switch" . }}
{{ end }}
<a href="{{ .Params.logIn.url }}" class="menu-link mx-3">{{ .Params.logIn.text }}</a>
<a href="{{ .Params.startFree.url }}" class="button button_contained button_sm">{{ .Params.startFree.text }}</a>
</div>
@@ -1,19 +1,19 @@
<div class="col-12 col-xl-2">
{{ if gt (.TableOfContents | len) 34 }}
<div class="table-contents">
<h2 class="table-contents__title">{{ .Params.title }}</h2>
<div class="table-of-contents">
<h2 class="table-of-contents__title">{{ .Params.title }}</h2>
{{ .TableOfContents }}
<ul class="table-contents__external-links">
<li class="table-contents__link">
<ul class="table-of-contents__external-links">
<li class="table-of-contents__link">
<a href="{{ .Site.Params.githubDocPrefix }}{{ path.Clean .File.Path }}" target="_blank">
{{ partial "svg" "github-red.svg" }}
Edit on Github
</a>
</li>
<li class="table-contents__link">
<li class="table-of-contents__link">
<a href="{{ .Site.Params.githubIssueLink }}" target="_blank">
{{ partial "svg" "bug-red.svg" }}
Create an issue
@@ -0,0 +1 @@
<button role="button" class="theme-switch"></button>
@@ -0,0 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-circle-half-2" width="44" height="44" viewBox="0 0 24 24" stroke-width="2" stroke="#6A80BD" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
<path d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0" />
<path d="M12 3v18" />
<path d="M12 14l7 -7" />
<path d="M12 19l8.5 -8.5" />
<path d="M12 9l4.5 -4.5" />
</svg>

After

Width:  |  Height:  |  Size: 470 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-moon"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path></svg>

After

Width:  |  Height:  |  Size: 281 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-sun"><circle cx="12" cy="12" r="5"></circle><line x1="12" y1="1" x2="12" y2="3"></line><line x1="12" y1="21" x2="12" y2="23"></line><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line><line x1="1" y1="12" x2="3" y2="12"></line><line x1="21" y1="12" x2="23" y2="12"></line><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line></svg>

After

Width:  |  Height:  |  Size: 650 B