Skip to content

Commit 98a4809

Browse files
authored
Finalize darklight mode switching 43 (#48)
Dark and Ligth mode skin is now easily switchable - mode can be switched from cookies (settings UI is not added yet, a separate GitHub issue has been added for it already) - fixed cases if masthead is turned off completely in the site config, the search must work nicely (with the hotkey) even if it is turned off - added support for tiny tooltips (similar to the classic short ones) that can have predefined text - added support for static tooltips (that remain steady even if the content is scrolled) - added some enhancements around hiding the tooltip Signed-off-by: Hofi <[email protected]>
2 parents 3db2fa1 + f9e3fd3 commit 98a4809

30 files changed

+763
-217
lines changed

_config.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,13 @@
22

33
remote_theme: mmistakes/[email protected]
44
#theme: minimal-mistakes-jekyll
5-
minimal_mistakes_skin: "midnight" # "default", "air", "aqua", "contrast", "dark", "dirt", "midnight", "mint", "neon", "plum", "sunrise"
5+
# Default minimal-mistakes skins
6+
# - # "default", "air", "aqua", "contrast", "dark", "dirt", "mint", "neon", "plum", "sunrise"
7+
# Additional skins
8+
# - "oi-midnight", "oi-light", "oi-dark"
9+
# NOTE: This one is not used at all, an d has no effect anymore, as we have our custom dynamic skin loading/swapping solution yet,
10+
# that is turned on by default via "skin_switchable: true"
11+
minimal_mistakes_skin: "oi-light"
612
skin_switchable: true
713

814
# Disable caching of content to disk in order to skip creating a .jekyll-cache or similar directory

_includes/globals.html

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
{% comment %}
2+
<!-- Global variables, scripts that require an early access, go through liquid parsimg, and/or cannot be moved to main.min.js-->
3+
{% endcomment %}
4+
5+
<script async="false">
6+
7+
const searchEnabled = {% if site.search == true %} true {% else %} false {% endif %};
8+
const hasMastHead = {% if site.masthead != false %} true {% else %} false {% endif %};
9+
const searchFromMastHead = {% if site.masthead != false and site.search_from_masthead == true %} true {% else %} false {% endif %};
10+
11+
const docRoot = '{{ site.baseurl }}';
12+
13+
function docPrefix() {
14+
return (docRoot != '' ? docRoot + '/' : '');
15+
}
16+
17+
function setCookie(name, value, days = 365 * 100) {
18+
var expires = "";
19+
if (days) {
20+
var date = new Date();
21+
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
22+
expires = "; expires=" + date.toUTCString();
23+
}
24+
document.cookie = name + "=" + (value || "") + expires + "; path=/; SameSite=Strict";
25+
}
26+
27+
function getCookie(name, defaultValue = null, saveIfMissing = false) {
28+
var nameEQ = name + "=";
29+
var ca = document.cookie.split(';');
30+
for (var i = 0; i < ca.length; i++) {
31+
var c = ca[i];
32+
while (c.charAt(0) == ' ') {
33+
c = c.substring(1, c.length);
34+
}
35+
if (c.indexOf(nameEQ) == 0) {
36+
return c.substring(nameEQ.length, c.length);
37+
}
38+
}
39+
if (saveIfMissing && defaultValue != null)
40+
setCookie(name, defaultValue);
41+
return defaultValue;
42+
}
43+
44+
function compareDOMRect(rect1, rect2) {
45+
return {
46+
top: rect1.top === rect2.top,
47+
right: rect1.right === rect2.right,
48+
bottom: rect1.bottom === rect2.bottom,
49+
left: rect1.left === rect2.left,
50+
width: rect1.width === rect2.width,
51+
height: rect1.height === rect2.height
52+
};
53+
}
54+
55+
function getElementPositionRelativeToRoot(element) {
56+
var rect = element.getBoundingClientRect();
57+
58+
// Calculate the position relative to the document
59+
var scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
60+
var scrollTop = window.pageYOffset || document.documentElement.scrollTop;
61+
62+
var position = {
63+
top: rect.top + scrollTop,
64+
left: rect.left + scrollLeft
65+
};
66+
return position;
67+
}
68+
69+
function comparePositions(pos1, pos2) {
70+
return pos1.top === pos2.top && pos1.left === pos2.left;
71+
}
72+
73+
</script>

_includes/head.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
<script>document.documentElement.className = document.documentElement.className.replace(/\bno-js\b/g, '') + ' js ';</script>
1212

13+
{% include globals.html %}
1314
{% include skins.html %}
1415

1516
<link rel="preload" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5/css/all.min.css" as="style" onload="this.onload=null;this.rel='stylesheet'">

_includes/masthead.html

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
11
{% capture logo_path %}{{ site.logo }}{% endcapture %}
22

33
<div class="masthead {% if site.masthead.sticky == true %}sticky{% endif %}">
4+
5+
{% comment %}<!--
6+
TODO: Far from perfect but working solution for now to have static (none moving) tooltips
7+
It's satisfying now as
8+
- we do have only in the masthead such controls
9+
- eliminates the need to add a real tooltip to each of the elements that require such a tooltip
10+
- it aids the detection of wether the tooltip needs to be hiding (e.g on tooltip movements caused by scrolling)
11+
-->{% endcomment %}
12+
<span id="tooltip" class="tooltip"></span>
13+
<span id="tooltipRenderer" class="tooltip visible"></span>
14+
415
<div class="masthead__inner-wrap">
516
<div class="masthead__menu">
617
<nav id="site-nav" class="greedy-nav">
@@ -36,11 +47,11 @@
3647
{% if site.search == true %}
3748
{% comment %}<!-- search__toggle is kept for backward compatibility -->{% endcomment %}
3849
<label class="sr-only" for="search-button">
39-
{{ site.data.ui-text[site.locale].search_label_text | default: 'Toggle search (Shift + Ctrl + F or ESC to close)' }}
50+
{{ site.data.ui-text[site.locale].search_label_text | default: 'Toggle search (`Shift + Ctrl + F`, ESC to close)' }}
4051
</label>
41-
<button id="search-button" class="masthead_button search__toggle" type="button">
42-
<span id="search_hint" class="">{{ site.data.ui-text[site.locale].search_label | default: "Toggle search (Shift + Ctrl + F or ESC to close)" }}</span>
43-
<i class="masthead_button_icon fas fa-search" style="font-size: 120%;"></i>
52+
<button id="search-button" class="masthead_button search__toggle" type="button" >
53+
<i class="masthead_button_icon content-tooltip tooltip-align-center text-content-tooltip fas fa-search" style="font-size: 120%;"
54+
data-tooltip-text="{{ site.data.ui-text[site.locale].search_label | default: 'Toggle search (`Shift + Ctrl + F`, ESC to close)' }}"></i>
4455
</button>
4556
{% endif %}
4657

_includes/search/search_form.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
{%- case search_provider -%}
44

55
{%- when "lunr" -%}
6-
{% if site.search_from_masthead == false %}
6+
{% if site.search_from_masthead == false or site.masthead == false %}
77
{% include /search/search_input.html %}
88
{% endif %}
9-
<div id="results" class="results {% if site.search_from_masthead %}from-masthead{% else %}from-search-content{% endif %}"></div>
9+
<div id="results" class="results {% if site.search_from_masthead and site.masthead != false %}from-masthead{% else %}from-search-content{% endif %}"></div>
1010

1111
{%- when "google" -%}
1212
{% include /search/search_input.html %}

_includes/search/search_input.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
{%- case search_provider -%}
33

44
{%- when "lunr" -%}
5-
<form class="search-content__form {% if site.search_from_masthead %}from-masthead{% else %}from-search-content{% endif %}"
5+
<form class="search-content__form {% if site.search_from_masthead and site.masthead != false %}from-masthead{% else %}from-search-content{% endif %}"
66
onkeydown="return event.key != 'Enter';" role="search">
77
<label class="sr-only" for="search">
88
{{ site.data.ui-text[site.locale].search_label_text | default: 'Enter your search term...' }}
99
</label>
10-
<input type="search" id="search" class="search-input {% if site.search_from_masthead %}from-masthead{% else %}from-search-content{% endif %}"
10+
<input type="search" id="search" class="search-input {% if site.search_from_masthead and site.masthead != false %}from-masthead{% else %}from-search-content{% endif %}"
1111
placeholder="{{ site.data.ui-text[site.locale].search_placeholder_text | default: 'Enter your search term...' }}" />
1212
<a class="search-help content-tooltip tooltip-align-center full-content-tooltip nav-link fas fa-info-circle" href="{{ '/lunr_search_help.html' | relative_url }}"></a>
1313
</form>

_includes/skins.html

Lines changed: 64 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
<!-- Dynamic loading of the user selected skin stylesheet -->
33
{% endcomment %}
44

5-
{% comment %}<!-- NOTE: the 'default' skin is in the 'main.css', see the main.scss file for details -->{% endcomment %}
6-
<link rel="stylesheet" id="skinedStylesheet" href="{{ '/assets/css/main.css' | relative_url }}">
5+
<link rel="stylesheet" id="skinedStylesheet" href="{{ '/assets/css/main_oi-light.css' | relative_url }}">
76

87
<style>
98
#full-page-container.full-page-container {
@@ -23,63 +22,74 @@
2322

2423
<script async="false">
2524

26-
const docRoot = '{{ site.baseurl }}';
27-
const darkSkin = 'midnight';
28-
const lightSkin = 'default';
29-
const searchEnabled = {% if site.search == true %} true {% else %} false {% endif %};
30-
const searchFromMastHead = {% if site.search_from_masthead == true %} true {% else %} false {% endif %};
25+
(function () {
26+
const defaultDarkSkin = 'oi-dark';
27+
const defaultLightSkin = 'oi-light';
3128

32-
function docPrefix() {
33-
return (docRoot != '' ? docRoot + '/' : '');
34-
}
29+
const selectedSkinStateKey = 'skin-state';
30+
const selectedSkinBackgroundColorKey = 'skin-background-color'
31+
const lightSkinKey = 'skin-light';
32+
const darkSkinKey = 'skin-dark';
33+
34+
const darkModeStateOn = 'dark';
35+
const darkModeStateOff = 'light';
36+
37+
//selectedLightSkin = 'default';
38+
//selectedDarkSkin = 'default';
39+
40+
function setSkinModeState(state) {
41+
const stylesheet = document.getElementById('skinedStylesheet');
42+
const skinName = getSkinForState(state);
3543

36-
function setCookie(name, value, days) {
37-
var expires = "";
38-
if (days) {
39-
var date = new Date();
40-
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
41-
expires = "; expires=" + date.toUTCString();
44+
// TODO: It seems it is not always triggered on a href value change once it is loaded/cached
45+
// We might have to force save the new color somehow in a different way as well
46+
// (Maybe a delayed saveColorChanges from window.addEventListener("load", ...) bellow ?!?!
47+
stylesheet.onload = saveColorChanges;
48+
stylesheet.href = docPrefix() + '/assets/css/main' + (skinName == 'default' ? '' : '_' + skinName) + '.css';
49+
50+
setCookie(selectedSkinStateKey, state);
4251
}
43-
document.cookie = name + "=" + (value || "") + expires + "; path=/; SameSite=Strict";
44-
}
4552

46-
function getCookie(name, defaultValue = null) {
47-
var nameEQ = name + "=";
48-
var ca = document.cookie.split(';');
49-
for (var i = 0; i < ca.length; i++) {
50-
var c = ca[i];
51-
while (c.charAt(0) == ' ') {
52-
c = c.substring(1, c.length);
53-
}
54-
if (c.indexOf(nameEQ) == 0) {
55-
return c.substring(nameEQ.length, c.length);
56-
}
53+
function getLightSkin() {
54+
return getCookie(lightSkinKey, defaultLightSkin, true);
5755
}
58-
return defaultValue;
59-
}
6056

61-
(function () {
62-
function setSkin(skin) {
63-
const stylesheet = document.getElementById('skinedStylesheet');
64-
//stylesheet.onload = saveChanges;
65-
stylesheet.href = docPrefix() + '/assets/css/main' + (skin == 'default' ? '' : '_' + skin) + '.css';
66-
setCookie('skin', skin, 365 * 100);
57+
function getDarkSkin() {
58+
return getCookie(darkSkinKey, defaultDarkSkin, true);
6759
}
6860

61+
function getSkinModeState() {
62+
return getCookie(selectedSkinStateKey, darkModeStateOff, true);
63+
}
64+
65+
function getSkinForState(state) {
66+
return state == darkModeStateOn ? getDarkSkin() : getLightSkin();
67+
}
68+
69+
function getSelectedSkin() {
70+
return getSkinForState(getSkinModeState());
71+
}
72+
6973
function toggleSkin(event) {
70-
if (getCookie('skin', 'default') == darkSkin) {
74+
const currentSkinState = getSkinModeState();
75+
if (currentSkinState == darkModeStateOff) {
7176
event.target.classList.remove('fa-toggle-on');
7277
event.target.classList.add('fa-toggle-off');
73-
setSkin(lightSkin);
7478
}
7579
else {
7680
event.target.classList.remove('fa-toggle-off');
7781
event.target.classList.add('fa-toggle-on');
78-
setSkin(darkSkin);
7982
}
83+
setSkinModeState(currentSkinState == darkModeStateOff ? darkModeStateOn : darkModeStateOff);
8084
event.currentTarget.blur();
8185
}
8286

87+
function saveColorChanges() {
88+
const htmlStyle = window.getComputedStyle(document.documentElement);
89+
const backgroundColor = htmlStyle.backgroundColor;
90+
setCookie(selectedSkinBackgroundColorKey, backgroundColor);
91+
};
92+
8393
function toggleIcon(target, off) {
8494
if (off) {
8595
target.classList.remove('fa-toggle-on');
@@ -92,12 +102,9 @@
92102
}
93103

94104
function toggleSkin(event) {
95-
var off = getCookie('skin', 'default') == darkSkin;
105+
var off = getSkinModeState() == darkModeStateOff;
96106

97-
if (off)
98-
setSkin(lightSkin);
99-
else
100-
setSkin(darkSkin);
107+
setSkinModeState(off ? darkModeStateOn : darkModeStateOff);
101108
toggleIcon(event.target, off);
102109

103110
event.currentTarget.blur();
@@ -107,36 +114,34 @@
107114
half rendered content parts (it is better to see an empty content even if it might appear in a different bacground color that the skin has)
108115
*/
109116
window.addEventListener("load", function () {
110-
function saveChanges() {
111-
const htmlStyle = window.getComputedStyle(document.documentElement);
112-
const backgroundColor = htmlStyle.backgroundColor;
113-
setCookie('skin-background-color', backgroundColor, 365 * 100);
114-
};
115-
116117
var container = document.getElementById("full-page-container");
117118
if (container)
118119
container.classList.remove('hidden');
119120

120121
// Why this is not working?!?!
121122
//document.body.style.removeProperty("backgroundColor");
122123
document.body.style.backgroundColor = "";
123-
if (storedSkin !== 'default')
124-
toggleIcon($('#skin-button').find('.masthead_button_icon')[0], false);
125-
124+
125+
toggleIcon($('#skin-button').find('.masthead_button_icon')[0], getSkinModeState());
126126
$("#skin-button").on("click", toggleSkin);
127127

128-
saveChanges();
128+
// TODO: See, setSkinModeState - stylesheet.onload
129+
// setTimeout(function () {
130+
// saveColorChanges();
131+
//}, 100);
129132
});
130133

131134
document.addEventListener("DOMContentLoaded", function () {
132-
const skinBackgroundColor = getCookie('skin-background-color');
135+
const skinBackgroundColor = getCookie(selectedSkinBackgroundColorKey);
133136
if (skinBackgroundColor)
134137
document.body.style.backgroundColor = skinBackgroundColor;
135138
});
136139

137-
const storedSkin = getCookie('skin', 'default');
138-
if (storedSkin !== 'default')
139-
setSkin(storedSkin);
140+
// These are just for always saving a default to the cookiestore if missing
141+
getLightSkin();
142+
getDarkSkin();
143+
144+
setSkinModeState(getSkinModeState());
140145

141146
})();
142147
</script>

0 commit comments

Comments
 (0)