Browse Source

Iterating on theme chooser

master
David Larlet 1 year ago
parent
commit
d4dc6f1821
No known key found for this signature in database
3 changed files with 141 additions and 87 deletions
  1. 50
    24
      david/index.html
  2. 1
    63
      david/templates/base_2020.html
  3. 90
    0
      david/templates/profil.html

+ 50
- 24
david/index.html View File

@@ -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>

+ 1
- 63
david/templates/base_2020.html View File

@@ -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>

+ 90
- 0
david/templates/profil.html View File

@@ -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 %}

Loading…
Cancel
Save