Skip to content

Commit

Permalink
Finalize darklight mode switching 43 (#48)
Browse files Browse the repository at this point in the history
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]>
  • Loading branch information
HofiOne authored May 17, 2024
2 parents 3db2fa1 + f9e3fd3 commit 98a4809
Show file tree
Hide file tree
Showing 30 changed files with 763 additions and 217 deletions.
8 changes: 7 additions & 1 deletion _config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@

remote_theme: mmistakes/[email protected]
#theme: minimal-mistakes-jekyll
minimal_mistakes_skin: "midnight" # "default", "air", "aqua", "contrast", "dark", "dirt", "midnight", "mint", "neon", "plum", "sunrise"
# Default minimal-mistakes skins
# - # "default", "air", "aqua", "contrast", "dark", "dirt", "mint", "neon", "plum", "sunrise"
# Additional skins
# - "oi-midnight", "oi-light", "oi-dark"
# 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,
# that is turned on by default via "skin_switchable: true"
minimal_mistakes_skin: "oi-light"
skin_switchable: true

# Disable caching of content to disk in order to skip creating a .jekyll-cache or similar directory
Expand Down
73 changes: 73 additions & 0 deletions _includes/globals.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
{% comment %}
<!-- Global variables, scripts that require an early access, go through liquid parsimg, and/or cannot be moved to main.min.js-->
{% endcomment %}

<script async="false">

const searchEnabled = {% if site.search == true %} true {% else %} false {% endif %};
const hasMastHead = {% if site.masthead != false %} true {% else %} false {% endif %};
const searchFromMastHead = {% if site.masthead != false and site.search_from_masthead == true %} true {% else %} false {% endif %};

const docRoot = '{{ site.baseurl }}';

function docPrefix() {
return (docRoot != '' ? docRoot + '/' : '');
}

function setCookie(name, value, days = 365 * 100) {
var expires = "";
if (days) {
var date = new Date();
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
expires = "; expires=" + date.toUTCString();
}
document.cookie = name + "=" + (value || "") + expires + "; path=/; SameSite=Strict";
}

function getCookie(name, defaultValue = null, saveIfMissing = false) {
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i];
while (c.charAt(0) == ' ') {
c = c.substring(1, c.length);
}
if (c.indexOf(nameEQ) == 0) {
return c.substring(nameEQ.length, c.length);
}
}
if (saveIfMissing && defaultValue != null)
setCookie(name, defaultValue);
return defaultValue;
}

function compareDOMRect(rect1, rect2) {
return {
top: rect1.top === rect2.top,
right: rect1.right === rect2.right,
bottom: rect1.bottom === rect2.bottom,
left: rect1.left === rect2.left,
width: rect1.width === rect2.width,
height: rect1.height === rect2.height
};
}

function getElementPositionRelativeToRoot(element) {
var rect = element.getBoundingClientRect();

// Calculate the position relative to the document
var scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
var scrollTop = window.pageYOffset || document.documentElement.scrollTop;

var position = {
top: rect.top + scrollTop,
left: rect.left + scrollLeft
};
return position;
}

function comparePositions(pos1, pos2) {
return pos1.top === pos2.top && pos1.left === pos2.left;
}

</script>
1 change: 1 addition & 0 deletions _includes/head.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

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

{% include globals.html %}
{% include skins.html %}

<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'">
Expand Down
19 changes: 15 additions & 4 deletions _includes/masthead.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
{% capture logo_path %}{{ site.logo }}{% endcapture %}

<div class="masthead {% if site.masthead.sticky == true %}sticky{% endif %}">

{% comment %}<!--
TODO: Far from perfect but working solution for now to have static (none moving) tooltips
It's satisfying now as
- we do have only in the masthead such controls
- eliminates the need to add a real tooltip to each of the elements that require such a tooltip
- it aids the detection of wether the tooltip needs to be hiding (e.g on tooltip movements caused by scrolling)
-->{% endcomment %}
<span id="tooltip" class="tooltip"></span>
<span id="tooltipRenderer" class="tooltip visible"></span>

<div class="masthead__inner-wrap">
<div class="masthead__menu">
<nav id="site-nav" class="greedy-nav">
Expand Down Expand Up @@ -36,11 +47,11 @@
{% if site.search == true %}
{% comment %}<!-- search__toggle is kept for backward compatibility -->{% endcomment %}
<label class="sr-only" for="search-button">
{{ site.data.ui-text[site.locale].search_label_text | default: 'Toggle search (Shift + Ctrl + F or ESC to close)' }}
{{ site.data.ui-text[site.locale].search_label_text | default: 'Toggle search (`Shift + Ctrl + F`, ESC to close)' }}
</label>
<button id="search-button" class="masthead_button search__toggle" type="button">
<span id="search_hint" class="">{{ site.data.ui-text[site.locale].search_label | default: "Toggle search (Shift + Ctrl + F or ESC to close)" }}</span>
<i class="masthead_button_icon fas fa-search" style="font-size: 120%;"></i>
<button id="search-button" class="masthead_button search__toggle" type="button" >
<i class="masthead_button_icon content-tooltip tooltip-align-center text-content-tooltip fas fa-search" style="font-size: 120%;"
data-tooltip-text="{{ site.data.ui-text[site.locale].search_label | default: 'Toggle search (`Shift + Ctrl + F`, ESC to close)' }}"></i>
</button>
{% endif %}

Expand Down
4 changes: 2 additions & 2 deletions _includes/search/search_form.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
{%- case search_provider -%}

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

{%- when "google" -%}
{% include /search/search_input.html %}
Expand Down
4 changes: 2 additions & 2 deletions _includes/search/search_input.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
{%- case search_provider -%}

{%- when "lunr" -%}
<form class="search-content__form {% if site.search_from_masthead %}from-masthead{% else %}from-search-content{% endif %}"
<form class="search-content__form {% if site.search_from_masthead and site.masthead != false %}from-masthead{% else %}from-search-content{% endif %}"
onkeydown="return event.key != 'Enter';" role="search">
<label class="sr-only" for="search">
{{ site.data.ui-text[site.locale].search_label_text | default: 'Enter your search term...' }}
</label>
<input type="search" id="search" class="search-input {% if site.search_from_masthead %}from-masthead{% else %}from-search-content{% endif %}"
<input type="search" id="search" class="search-input {% if site.search_from_masthead and site.masthead != false %}from-masthead{% else %}from-search-content{% endif %}"
placeholder="{{ site.data.ui-text[site.locale].search_placeholder_text | default: 'Enter your search term...' }}" />
<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>
</form>
Expand Down
123 changes: 64 additions & 59 deletions _includes/skins.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
<!-- Dynamic loading of the user selected skin stylesheet -->
{% endcomment %}

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

<style>
#full-page-container.full-page-container {
Expand All @@ -23,63 +22,74 @@

<script async="false">

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

function docPrefix() {
return (docRoot != '' ? docRoot + '/' : '');
}
const selectedSkinStateKey = 'skin-state';
const selectedSkinBackgroundColorKey = 'skin-background-color'
const lightSkinKey = 'skin-light';
const darkSkinKey = 'skin-dark';

const darkModeStateOn = 'dark';
const darkModeStateOff = 'light';

//selectedLightSkin = 'default';
//selectedDarkSkin = 'default';

function setSkinModeState(state) {
const stylesheet = document.getElementById('skinedStylesheet');
const skinName = getSkinForState(state);

function setCookie(name, value, days) {
var expires = "";
if (days) {
var date = new Date();
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
expires = "; expires=" + date.toUTCString();
// TODO: It seems it is not always triggered on a href value change once it is loaded/cached
// We might have to force save the new color somehow in a different way as well
// (Maybe a delayed saveColorChanges from window.addEventListener("load", ...) bellow ?!?!
stylesheet.onload = saveColorChanges;
stylesheet.href = docPrefix() + '/assets/css/main' + (skinName == 'default' ? '' : '_' + skinName) + '.css';

setCookie(selectedSkinStateKey, state);
}
document.cookie = name + "=" + (value || "") + expires + "; path=/; SameSite=Strict";
}

function getCookie(name, defaultValue = null) {
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i];
while (c.charAt(0) == ' ') {
c = c.substring(1, c.length);
}
if (c.indexOf(nameEQ) == 0) {
return c.substring(nameEQ.length, c.length);
}
function getLightSkin() {
return getCookie(lightSkinKey, defaultLightSkin, true);
}
return defaultValue;
}

(function () {
function setSkin(skin) {
const stylesheet = document.getElementById('skinedStylesheet');
//stylesheet.onload = saveChanges;
stylesheet.href = docPrefix() + '/assets/css/main' + (skin == 'default' ? '' : '_' + skin) + '.css';
setCookie('skin', skin, 365 * 100);
function getDarkSkin() {
return getCookie(darkSkinKey, defaultDarkSkin, true);
}

function getSkinModeState() {
return getCookie(selectedSkinStateKey, darkModeStateOff, true);
}

function getSkinForState(state) {
return state == darkModeStateOn ? getDarkSkin() : getLightSkin();
}

function getSelectedSkin() {
return getSkinForState(getSkinModeState());
}

function toggleSkin(event) {
if (getCookie('skin', 'default') == darkSkin) {
const currentSkinState = getSkinModeState();
if (currentSkinState == darkModeStateOff) {
event.target.classList.remove('fa-toggle-on');
event.target.classList.add('fa-toggle-off');
setSkin(lightSkin);
}
else {
event.target.classList.remove('fa-toggle-off');
event.target.classList.add('fa-toggle-on');
setSkin(darkSkin);
}
setSkinModeState(currentSkinState == darkModeStateOff ? darkModeStateOn : darkModeStateOff);
event.currentTarget.blur();
}

function saveColorChanges() {
const htmlStyle = window.getComputedStyle(document.documentElement);
const backgroundColor = htmlStyle.backgroundColor;
setCookie(selectedSkinBackgroundColorKey, backgroundColor);
};

function toggleIcon(target, off) {
if (off) {
target.classList.remove('fa-toggle-on');
Expand All @@ -92,12 +102,9 @@
}

function toggleSkin(event) {
var off = getCookie('skin', 'default') == darkSkin;
var off = getSkinModeState() == darkModeStateOff;

if (off)
setSkin(lightSkin);
else
setSkin(darkSkin);
setSkinModeState(off ? darkModeStateOn : darkModeStateOff);
toggleIcon(event.target, off);

event.currentTarget.blur();
Expand All @@ -107,36 +114,34 @@
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)
*/
window.addEventListener("load", function () {
function saveChanges() {
const htmlStyle = window.getComputedStyle(document.documentElement);
const backgroundColor = htmlStyle.backgroundColor;
setCookie('skin-background-color', backgroundColor, 365 * 100);
};

var container = document.getElementById("full-page-container");
if (container)
container.classList.remove('hidden');

// Why this is not working?!?!
//document.body.style.removeProperty("backgroundColor");
document.body.style.backgroundColor = "";
if (storedSkin !== 'default')
toggleIcon($('#skin-button').find('.masthead_button_icon')[0], false);


toggleIcon($('#skin-button').find('.masthead_button_icon')[0], getSkinModeState());
$("#skin-button").on("click", toggleSkin);

saveChanges();
// TODO: See, setSkinModeState - stylesheet.onload
// setTimeout(function () {
// saveColorChanges();
//}, 100);
});

document.addEventListener("DOMContentLoaded", function () {
const skinBackgroundColor = getCookie('skin-background-color');
const skinBackgroundColor = getCookie(selectedSkinBackgroundColorKey);
if (skinBackgroundColor)
document.body.style.backgroundColor = skinBackgroundColor;
});

const storedSkin = getCookie('skin', 'default');
if (storedSkin !== 'default')
setSkin(storedSkin);
// These are just for always saving a default to the cookiestore if missing
getLightSkin();
getDarkSkin();

setSkinModeState(getSkinModeState());

})();
</script>
Loading

0 comments on commit 98a4809

Please sign in to comment.