mirror of
https://github.com/phil-opp/blog_os.git
synced 2025-12-16 14:27:49 +00:00
Merge pull request #1059 from phil-opp/dark-mode
Remember chosen theme in `localStorage`, add a switch for going back to system theme, improve layout
This commit is contained in:
@@ -92,7 +92,7 @@ body {
|
||||
@include set-colors-light();
|
||||
}
|
||||
|
||||
body.dark {
|
||||
[data-theme="dark"] body {
|
||||
@include set-colors-dark();
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ body.dark {
|
||||
@include set-colors-dark();
|
||||
}
|
||||
/* Override dark mode with light mode styles if the user decides to swap */
|
||||
body.light {
|
||||
[data-theme="light"] body {
|
||||
@include set-colors-light();
|
||||
}
|
||||
}
|
||||
@@ -966,7 +966,7 @@ img {
|
||||
.dark-mode-note {
|
||||
display: none;
|
||||
}
|
||||
body.dark .dark-mode-note {
|
||||
[data-theme="dark"] .dark-mode-note {
|
||||
display: block;
|
||||
}
|
||||
@media (prefers-color-scheme: dark) {
|
||||
@@ -975,52 +975,103 @@ body.dark .dark-mode-note {
|
||||
display: block;
|
||||
}
|
||||
/* Override dark mode with light mode styles if the user decides to swap */
|
||||
body.light .dark-mode-note {
|
||||
[data-theme="light"] .dark-mode-note {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Manual switch between dark and light mode */
|
||||
|
||||
@mixin light-switch-light {
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23004' class='bi bi-moon' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M14.53 10.53a7 7 0 0 1-9.058-9.058A7.003 7.003 0 0 0 8 15a7.002 7.002 0 0 0 6.53-4.47z'/%3E%3C/svg%3E");
|
||||
}
|
||||
.theme-switch {
|
||||
margin-bottom: 1rem;
|
||||
|
||||
@mixin light-switch-dark {
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23ff9' class='bi bi-brightness-high-fill' viewBox='0 0 16 16'%3E%3Cpath d='M12 8a4 4 0 1 1-8 0 4 4 0 0 1 8 0zM8 0a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 0zm0 13a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 13zm8-5a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2a.5.5 0 0 1 .5.5zM3 8a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2A.5.5 0 0 1 3 8zm10.657-5.657a.5.5 0 0 1 0 .707l-1.414 1.415a.5.5 0 1 1-.707-.708l1.414-1.414a.5.5 0 0 1 .707 0zm-9.193 9.193a.5.5 0 0 1 0 .707L3.05 13.657a.5.5 0 0 1-.707-.707l1.414-1.414a.5.5 0 0 1 .707 0zm9.193 2.121a.5.5 0 0 1-.707 0l-1.414-1.414a.5.5 0 0 1 .707-.707l1.414 1.414a.5.5 0 0 1 0 .707zM4.464 4.465a.5.5 0 0 1-.707 0L2.343 3.05a.5.5 0 1 1 .707-.707l1.414 1.414a.5.5 0 0 1 0 .708z'/%3E%3C/svg%3E");
|
||||
@media (min-width: 80rem) {
|
||||
position: fixed;
|
||||
left: 2rem;
|
||||
bottom: 2rem;
|
||||
margin-bottom: 0rem;
|
||||
}
|
||||
}
|
||||
|
||||
.light-switch {
|
||||
@mixin light-switch-light {
|
||||
// icon: https://icons.getbootstrap.com/icons/moon-fill/ (MIT licensed)
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23004' class='bi bi-moon' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M14.53 10.53a7 7 0 0 1-9.058-9.058A7.003 7.003 0 0 0 8 15a7.002 7.002 0 0 0 6.53-4.47z'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
@mixin light-switch-dark {
|
||||
// icon: https://icons.getbootstrap.com/icons/brightness-high-fill/ (MIT licensed)
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23ff9' class='bi bi-brightness-high-fill' viewBox='0 0 16 16'%3E%3Cpath d='M12 8a4 4 0 1 1-8 0 4 4 0 0 1 8 0zM8 0a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 0zm0 13a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 13zm8-5a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2a.5.5 0 0 1 .5.5zM3 8a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2A.5.5 0 0 1 3 8zm10.657-5.657a.5.5 0 0 1 0 .707l-1.414 1.415a.5.5 0 1 1-.707-.708l1.414-1.414a.5.5 0 0 1 .707 0zm-9.193 9.193a.5.5 0 0 1 0 .707L3.05 13.657a.5.5 0 0 1-.707-.707l1.414-1.414a.5.5 0 0 1 .707 0zm9.193 2.121a.5.5 0 0 1-.707 0l-1.414-1.414a.5.5 0 0 1 .707-.707l1.414 1.414a.5.5 0 0 1 0 .707zM4.464 4.465a.5.5 0 0 1-.707 0L2.343 3.05a.5.5 0 1 1 .707-.707l1.414 1.414a.5.5 0 0 1 0 .708z'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
display: inline-block;
|
||||
@include light-switch-light();
|
||||
}
|
||||
|
||||
body.dark .light-switch {
|
||||
@include light-switch-dark();
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.light-switch {
|
||||
@include light-switch-dark();
|
||||
}
|
||||
|
||||
body.light .light-switch {
|
||||
@include light-switch-light();
|
||||
}
|
||||
}
|
||||
|
||||
.light-switch {
|
||||
position: fixed;
|
||||
left: 2rem;
|
||||
bottom: 2rem;
|
||||
background-repeat: no-repeat;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
cursor: pointer;
|
||||
opacity: 0.6;
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.3);
|
||||
transition: 200ms ease-out;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
[data-theme="dark"] & {
|
||||
@include light-switch-dark();
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
@include light-switch-dark();
|
||||
|
||||
[data-theme="light"] & {
|
||||
@include light-switch-light();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.light-switch:hover {
|
||||
transform: scale(1.3);
|
||||
transition: 200ms ease-out;
|
||||
opacity: 1;
|
||||
/* Clear theme override and go back to system theme */
|
||||
|
||||
.light-switch-reset {
|
||||
@mixin light-switch-reset-light {
|
||||
// icon: https://icons.getbootstrap.com/icons/x-circle-fill/ (MIT licensed)
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='%23666' class='bi bi-x-circle' viewBox='0 0 16 16'%3E%3Cpath d='M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z'/%3E%3Cpath d='M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
@mixin light-switch-reset-dark {
|
||||
// icon: https://icons.getbootstrap.com/icons/x-circle-fill/ (MIT licensed)
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='%23999' class='bi bi-x-circle' viewBox='0 0 16 16'%3E%3Cpath d='M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z'/%3E%3Cpath d='M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
@include light-switch-reset-light();
|
||||
vertical-align: bottom;
|
||||
margin-left: 0.5rem;
|
||||
background-repeat: no-repeat;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
cursor: pointer;
|
||||
opacity: 0.6;
|
||||
|
||||
display: none;
|
||||
[data-theme="light"] & {
|
||||
display: inline-block;
|
||||
}
|
||||
[data-theme="dark"] & {
|
||||
@include light-switch-reset-dark();
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
@media (min-width: 80rem) {
|
||||
position: fixed;
|
||||
left: 4.5rem;
|
||||
bottom: 2rem;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.1);
|
||||
transition: 200ms ease-out;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,21 @@
|
||||
window.onload = function() {
|
||||
var container = document.querySelector('#toc-aside');
|
||||
window.onload = function () {
|
||||
let theme = localStorage.getItem("theme");
|
||||
if (theme != null) {
|
||||
set_theme(theme)
|
||||
}
|
||||
|
||||
let container = document.querySelector('#toc-aside');
|
||||
if (container != null) {
|
||||
resize_toc(container);
|
||||
toc_scroll_position(container);
|
||||
window.onscroll = function() { toc_scroll_position(container) };
|
||||
window.onscroll = function () { toc_scroll_position(container) };
|
||||
}
|
||||
}
|
||||
|
||||
function resize_toc(container) {
|
||||
var containerHeight = container.clientHeight;
|
||||
let containerHeight = container.clientHeight;
|
||||
|
||||
var resize = function() {
|
||||
let resize = function () {
|
||||
if (containerHeight > document.documentElement.clientHeight - 100) {
|
||||
container.classList.add('coarse');
|
||||
} else {
|
||||
@@ -20,8 +24,8 @@ function resize_toc(container) {
|
||||
};
|
||||
resize();
|
||||
|
||||
var resizeId;
|
||||
window.onresize = function() {
|
||||
let resizeId;
|
||||
window.onresize = function () {
|
||||
clearTimeout(resizeId);
|
||||
resizeId = setTimeout(resize, 300);
|
||||
};
|
||||
@@ -32,7 +36,6 @@ function toc_scroll_position(container) {
|
||||
// skip computation if ToC is not visible
|
||||
return;
|
||||
}
|
||||
var items = container.querySelectorAll("li")
|
||||
|
||||
// remove active class for all items
|
||||
for (item of container.querySelectorAll("li")) {
|
||||
@@ -40,15 +43,15 @@ function toc_scroll_position(container) {
|
||||
}
|
||||
|
||||
// look for active item
|
||||
var site_offset = document.documentElement.scrollTop;
|
||||
var current_toc_item = null;
|
||||
let site_offset = document.documentElement.scrollTop;
|
||||
let current_toc_item = null;
|
||||
for (item of container.querySelectorAll("li")) {
|
||||
if (item.offsetParent === null) {
|
||||
// skip items that are not visible
|
||||
continue;
|
||||
}
|
||||
var anchor = item.firstElementChild.getAttribute("href");
|
||||
var heading = document.querySelector(anchor);
|
||||
let anchor = item.firstElementChild.getAttribute("href");
|
||||
let heading = document.querySelector(anchor);
|
||||
if (heading.offsetTop <= (site_offset + document.documentElement.clientHeight / 3)) {
|
||||
current_toc_item = item;
|
||||
} else {
|
||||
@@ -63,25 +66,33 @@ function toc_scroll_position(container) {
|
||||
}
|
||||
|
||||
function toggle_lights() {
|
||||
var body = document.querySelector("body");
|
||||
var comment_form = document.querySelector("iframe.giscus-frame");
|
||||
if (body != null) {
|
||||
if (body.classList.contains("dark")) {
|
||||
body.classList.replace("dark", "light");
|
||||
if (comment_form != null) {
|
||||
comment_form.contentWindow.postMessage({
|
||||
giscus: { setConfig: { theme: 'light' } }
|
||||
}, "https://giscus.app")
|
||||
}
|
||||
} else {
|
||||
body.classList.remove("light");
|
||||
body.classList.add("dark");
|
||||
if (comment_form != null) {
|
||||
comment_form.contentWindow.postMessage({
|
||||
giscus: { setConfig: { theme: 'dark' } }
|
||||
}, "https://giscus.app")
|
||||
}
|
||||
}
|
||||
console.log(body)
|
||||
if (document.documentElement.getAttribute("data-theme") === "dark") {
|
||||
set_theme("light")
|
||||
} else if (document.documentElement.getAttribute("data-theme") === "light") {
|
||||
set_theme("dark")
|
||||
} else {
|
||||
set_theme(window.matchMedia("(prefers-color-scheme: dark)").matches ? "light" : "dark")
|
||||
}
|
||||
}
|
||||
|
||||
function set_theme(theme) {
|
||||
document.documentElement.setAttribute("data-theme", theme)
|
||||
set_giscus_theme(theme)
|
||||
localStorage.setItem("theme", theme)
|
||||
}
|
||||
|
||||
function clear_theme_override() {
|
||||
document.documentElement.removeAttribute("data-theme");
|
||||
set_giscus_theme("preferred_color_scheme")
|
||||
localStorage.removeItem("theme")
|
||||
}
|
||||
|
||||
function set_giscus_theme(theme) {
|
||||
let comment_form = document.querySelector("iframe.giscus-frame");
|
||||
if (comment_form != null) {
|
||||
comment_form.contentWindow.postMessage({
|
||||
giscus: { setConfig: { theme: theme } }
|
||||
}, "https://giscus.app")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,13 @@
|
||||
|
||||
<link rel="alternate" type="application/rss+xml" title="RSS feed for os.phil-opp.com" href="{{ config.base_url | safe }}/rss.xml" />
|
||||
|
||||
<script>
|
||||
let theme = localStorage.getItem("theme");
|
||||
if (theme != null) {
|
||||
document.documentElement.setAttribute("data-theme", theme);
|
||||
}
|
||||
</script>
|
||||
|
||||
<script async src="/js/edition-2/main.js"></script>
|
||||
|
||||
<title>{% block title %}{% endblock title %}</title>
|
||||
@@ -34,6 +41,11 @@
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="theme-switch">
|
||||
<div class="light-switch" onclick="toggle_lights()" title="Switch between light and dark theme"></div>
|
||||
<div class="light-switch-reset" onclick="clear_theme_override()" title="Clear the theme override and go back to the system theme"></div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{% block toc_aside %}{% endblock toc_aside %}
|
||||
<main>{% block main %}{% endblock main %}</main>
|
||||
@@ -50,8 +62,6 @@
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
<div class="light-switch" onclick="toggle_lights()" title="Switch between light and dark theme"></div>
|
||||
|
||||
<script data-goatcounter="https://phil-opp.goatcounter.com/count" async src="//gc.zgo.at/count.js"></script>
|
||||
</body>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user