@@ -129,7 +129,7 @@ | |||
<script src="/static/david/js/instantpage-3.0.0.min.js" type="module" defer></script> | |||
<template id="theme-selector"> | |||
<form id="chosen-color-scheme"> | |||
<form> | |||
<fieldset> | |||
<legend>Thème</legend> | |||
<label> | |||
@@ -148,47 +148,73 @@ | |||
/* This is a work in progress with Anthony https://ricaud.me */ | |||
// TODISCUSS: | |||
// 1. give a way for the user to close that choice? | |||
// 2. store preferences? (in a cookie or localstorage) | |||
// 1. give a way for the user to close that chooser? | |||
// 2. store preferences? (in a cookie or localstorage or sessionStorage) | |||
// 3. create the template from scratch in JS? | |||
// 4. how to deal with multiple rules by stylesheet? | |||
const themeSelectorTemplate = document.querySelector('#theme-selector') | |||
const clone = themeSelectorTemplate.content.cloneNode(true) | |||
const firstChild = clone.firstElementChild | |||
document.body.insertAdjacentElement('afterbegin', firstChild) | |||
const form = document.querySelector('form#chosen-color-scheme') | |||
form.addEventListener('change', (e) => { | |||
const chosenColorScheme = e.target.value | |||
document.body.classList.toggle('forced-dark', chosenColorScheme === 'dark') | |||
document.body.classList.toggle( | |||
'forced-light', | |||
chosenColorScheme === 'light' | |||
// 4. how to make it generic? (no need for forced-dark/light existing rules) | |||
// Results from a Poll: https://mastodon.social/@dav/104093540923157521 | |||
// Avoir un moyen de changer de thème d'un site à la main : | |||
// 49% => Utile | |||
// 23% => Pas utile | |||
// 9% => So 2000 | |||
// 19% => Je veux le même | |||
// After 24 hours and 43 votes | |||
// A bit hard to interpret, I guess people wanting it found it useful too! | |||
function loadThemeForm(templateName) { | |||
const themeSelectorTemplate = document.querySelector(templateName) | |||
const clone = themeSelectorTemplate.content.cloneNode(true) | |||
const form = document.body.insertAdjacentElement( | |||
'afterbegin', | |||
clone.firstElementChild | |||
) | |||
}) | |||
form.addEventListener('change', (e) => { | |||
const chosenColorScheme = e.target.value | |||
document.body.classList.toggle( | |||
'forced-dark', | |||
chosenColorScheme === 'dark' | |||
) | |||
document.body.classList.toggle( | |||
'forced-light', | |||
chosenColorScheme === 'light' | |||
) | |||
}) | |||
} | |||
const mediaQueryTest = '(prefers-color-scheme: dark)' | |||
window.addEventListener('load', () => { | |||
// TODO: do not display the form if there is no related media CSS rule. | |||
for (const styleSheet of [...document.styleSheets]) { | |||
let mediaRules = [] | |||
let ruleFound = false | |||
for (const styleSheet of Array.from(document.styleSheets)) { | |||
for (const cssRule of styleSheet.cssRules) { | |||
if (cssRule.type !== CSSRule.MEDIA_RULE) continue | |||
// Warning, Safari does not have/supports `conditionText`. | |||
// WARNING: Safari does not have/supports `conditionText`. | |||
if (cssRule.conditionText) { | |||
if (cssRule.conditionText !== mediaQueryTest) continue | |||
} else { | |||
if (cssRule.cssText.startsWith(mediaQueryTest)) continue | |||
} | |||
// At that point, only a media cssRule matching our media query | |||
// test should remain, hence the renaming. | |||
const mediaRule = cssRule | |||
for (const innerCssRule of mediaRule.cssRules) { | |||
styleSheet.insertRule(innerCssRule.cssText) | |||
mediaRules.push(innerCssRule) | |||
ruleFound = true | |||
} | |||
// TODO: what if there are more than one declaration? | |||
break | |||
} | |||
// WARNING: do not try to insert a Rule to a styleSheet you are | |||
// currently iterating on, otherwise the browser will be stuck | |||
// in a infinite loop… | |||
for (const mediaRule of mediaRules) { | |||
styleSheet.insertRule(mediaRule.cssText) | |||
} | |||
mediaRules = [] | |||
} | |||
if (ruleFound) loadThemeForm('#theme-selector') | |||
}) | |||
</script> | |||
</body> | |||
</html> |
@@ -45,68 +45,6 @@ | |||
</p> | |||
</footer> | |||
<script src="/static/david/js/instantpage-3.0.0.min.js" type="module" defer></script> | |||
<template id="theme-selector"> | |||
<form id="chosen-color-scheme"> | |||
<fieldset> | |||
<legend>Thème</legend> | |||
<label> | |||
<input type="radio" value="auto" name="chosen-color-scheme" checked> Auto | |||
</label> | |||
<label> | |||
<input type="radio" value="dark" name="chosen-color-scheme"> Foncé | |||
</label> | |||
<label> | |||
<input type="radio" value="light" name="chosen-color-scheme"> Clair | |||
</label> | |||
</fieldset> | |||
</form> | |||
</template> | |||
<script type="text/javascript"> | |||
/* This is a work in progress with Anthony https://ricaud.me */ | |||
// TODISCUSS: | |||
// 1. give a way for the user to close that choice? | |||
// 2. store preferences? (in a cookie or localstorage) | |||
// 3. create the template from scratch in JS? | |||
// 4. how to deal with multiple rules by stylesheet? | |||
const themeSelectorTemplate = document.querySelector('#theme-selector') | |||
const clone = themeSelectorTemplate.content.cloneNode(true) | |||
const firstChild = clone.firstElementChild | |||
document.body.insertAdjacentElement('afterbegin', firstChild) | |||
const form = document.querySelector('form#chosen-color-scheme') | |||
form.addEventListener('change', (e) => { | |||
const chosenColorScheme = e.target.value | |||
document.body.classList.toggle('forced-dark', chosenColorScheme === 'dark') | |||
document.body.classList.toggle( | |||
'forced-light', | |||
chosenColorScheme === 'light' | |||
) | |||
}) | |||
const mediaQueryTest = '(prefers-color-scheme: dark)' | |||
window.addEventListener('load', () => { | |||
// TODO: do not display the form if there is no related media CSS rule. | |||
for (const styleSheet of [...document.styleSheets]) { | |||
for (const cssRule of styleSheet.cssRules) { | |||
if (cssRule.type !== CSSRule.MEDIA_RULE) continue | |||
// Warning, Safari does not have/supports `conditionText`. | |||
if (cssRule.conditionText) { | |||
if (cssRule.conditionText !== mediaQueryTest) continue | |||
} else { | |||
if (cssRule.cssText.startsWith(mediaQueryTest)) continue | |||
} | |||
const mediaRule = cssRule | |||
for (const innerCssRule of mediaRule.cssRules) { | |||
styleSheet.insertRule(innerCssRule.cssText) | |||
} | |||
// TODO: what if there are more than one declaration? | |||
break | |||
} | |||
} | |||
}) | |||
</script> | |||
{% block extra_bottom %}{% endblock extra_bottom %} | |||
</body> | |||
</html> |
@@ -52,3 +52,93 @@ | |||
</article> | |||
{% endblock content %} | |||
{% block extra_bottom %} | |||
<template id="theme-selector"> | |||
<form> | |||
<fieldset> | |||
<legend>Thème</legend> | |||
<label> | |||
<input type="radio" value="auto" name="chosen-color-scheme" checked> Auto | |||
</label> | |||
<label> | |||
<input type="radio" value="dark" name="chosen-color-scheme"> Foncé | |||
</label> | |||
<label> | |||
<input type="radio" value="light" name="chosen-color-scheme"> Clair | |||
</label> | |||
</fieldset> | |||
</form> | |||
</template> | |||
<script type="text/javascript"> | |||
/* This is a work in progress with Anthony https://ricaud.me */ | |||
// TODISCUSS: | |||
// 1. give a way for the user to close that chooser? | |||
// 2. store preferences? (in a cookie or localstorage or sessionStorage) | |||
// 3. create the template from scratch in JS? | |||
// 4. how to make it generic? (no need for forced-dark/light existing rules) | |||
// Results from a Poll: https://mastodon.social/@dav/104093540923157521 | |||
// Avoir un moyen de changer de thème d'un site à la main : | |||
// 49% => Utile | |||
// 23% => Pas utile | |||
// 9% => So 2000 | |||
// 19% => Je veux le même | |||
// After 24 hours and 43 votes | |||
// A bit hard to interpret, I guess people wanting it found it useful too! | |||
function loadThemeForm(templateName) { | |||
const themeSelectorTemplate = document.querySelector(templateName) | |||
const clone = themeSelectorTemplate.content.cloneNode(true) | |||
const form = document.body.insertAdjacentElement( | |||
'afterbegin', | |||
clone.firstElementChild | |||
) | |||
form.addEventListener('change', (e) => { | |||
const chosenColorScheme = e.target.value | |||
document.body.classList.toggle( | |||
'forced-dark', | |||
chosenColorScheme === 'dark' | |||
) | |||
document.body.classList.toggle( | |||
'forced-light', | |||
chosenColorScheme === 'light' | |||
) | |||
}) | |||
} | |||
const mediaQueryTest = '(prefers-color-scheme: dark)' | |||
window.addEventListener('load', () => { | |||
let mediaRules = [] | |||
let ruleFound = false | |||
for (const styleSheet of Array.from(document.styleSheets)) { | |||
for (const cssRule of styleSheet.cssRules) { | |||
if (cssRule.type !== CSSRule.MEDIA_RULE) continue | |||
// WARNING: Safari does not have/supports `conditionText`. | |||
if (cssRule.conditionText) { | |||
if (cssRule.conditionText !== mediaQueryTest) continue | |||
} else { | |||
if (cssRule.cssText.startsWith(mediaQueryTest)) continue | |||
} | |||
// At that point, only a media cssRule matching our media query | |||
// test should remain, hence the renaming. | |||
const mediaRule = cssRule | |||
for (const innerCssRule of mediaRule.cssRules) { | |||
mediaRules.push(innerCssRule) | |||
ruleFound = true | |||
} | |||
} | |||
// WARNING: do not try to insert a Rule to a styleSheet you are | |||
// currently iterating on, otherwise the browser will be stuck | |||
// in a infinite loop… | |||
for (const mediaRule of mediaRules) { | |||
styleSheet.insertRule(mediaRule.cssText) | |||
} | |||
mediaRules = [] | |||
} | |||
if (ruleFound) loadThemeForm('#theme-selector') | |||
}) | |||
</script> | |||
{% endblock extra_bottom %} |