variant: allow page browsing with custom theme #188

This commit is contained in:
Sören Weber 2022-02-21 23:11:04 +01:00
parent f2b09e0980
commit 78abe914e0
No known key found for this signature in database
GPG key ID: 07D17FF580AE7589
7 changed files with 204 additions and 93 deletions

View file

@ -168,7 +168,7 @@ Then, set the `themeVariant` value with the name of your custom theme file. That
### Multiple variants
You can also set multiple variants. In this case, the first variant is the default choosen on first view and a theme switch will be shown in the menu footer.
You can also set multiple variants. In this case, the first variant is the default choosen on first view and a variant switch will be shown in the menu footer.
```toml
[params]

View file

@ -13,16 +13,19 @@ The arrowed lines reflect how colors are inherited thru different parts of the t
To better understand this select the `neon` variant and modify the differnet heading colors. There, colors for the heading `h2`, `h3` and `h4` are explicitly set. `h5` is not set and inherits its value from `h4`. `h6` is also not set and inherits its value from `h5`.
Once you've changed a color, the theme selector will show a "My custom variant" entry and your changes are stored. You can change pages and even close the browser without losing your changes.
Once you are satisfied, you can download the new variants file and install it in your site.
{{% notice note %}}
You need to define at least one `themeVariant` in your `config.toml` to modify and download the styles.
This only works in modern browsers.
{{% /notice %}}
## Variant generator
<a class="vardownload btn btn-default">Download color variant</a>
<a class="varreset btn btn-default">Reset variant</a>
<div id="vargenerator" class="mermaid" style="background-color: var(--INTERNAL-MAIN-TEXT-color);" align="center">Graph</div>
<a class="vardownload btn btn-default">Download color variant</a>

View file

@ -24,7 +24,7 @@ This document shows you what's new in the latest release. For a detailed list of
This change will only affect your installation if you've not set the `themeVariant` parameter in your `config.toml`. [If you still want to use the Learn color variant]({{%relref "basics/customization/#learn-variant" %}}), you have to explicitly set `themeVariant="learn"` in your `config.toml`.
Note, that this will also affect your site if viewed with Internet Explorer 11 and can not be reconfigured as it does not support CSS variables.
Note, that this will also affect your site if viewed with Internet Explorer 11 but in this case it can not be reconfigured as Internet Explorer does not support CSS variables.
- **Change**: Due to a bug, that we couldn't fix in a general manner for color variants, we decided to remove `--MENU-SEARCH-BOX-ICONS-color`.
@ -36,9 +36,9 @@ This document shows you what's new in the latest release. For a detailed list of
- **New**: To make the creation of new variants easier for you, we've added a new interactive [theme variant generator]({{%relref "basics/generator" %}}).
- **New**: You can now configure multiple color variants in your `config.toml`. In this case, the first variant is the default chosen on first view and a theme switch will be shown in the menu footer. See the [documentation]({{%relref "basics/customization/#multiple-variants" %}}) for configuration.
- **New**: You can now configure multiple color variants in your `config.toml`. In this case, the first variant is the default chosen on first view and a variant switch will be shown in the menu footer. See the [documentation]({{%relref "basics/customization/#multiple-variants" %}}) for configuration.
Note, that the new theme switch will not work with Internet Explorer 11 as it does not support CSS variables.
Note, that the new variant switch will not work with Internet Explorer 11 as it does not support CSS variables.
## 2.9.0

View file

@ -52,26 +52,22 @@
</ul>
</div>
{{- end }}
<div class="footermargin"></div>
{{- $showlangswitch := and .Site.IsMultiLingual (not .Site.Params.disableLanguageSwitchingButton) }}
{{- $themevariants := slice | append .Site.Params.themeVariant }}
{{- $showthemeswitch := gt (int (len $themevariants)) 1 }}
{{- $siteLanguages := .Site.Languages }}
{{- $showlangswitch := and .Site.IsMultiLingual (not .Site.Params.disableLanguageSwitchingButton) (gt (int (len $siteLanguages)) 1) }}
{{- $themevariants := slice | append (.Site.Params.themeVariant | default "relearn-light" ) }}
{{- $showvariantswitch := gt (int (len $themevariants)) 1 }}
{{- $footer := partial "menu-footer.html" . }}
{{- $showfooter := not (eq 0 (int (len ($footer | plainify)))) }}
{{- if or $showlangswitch $showvisitedlinks $showfooter }}
<hr class="default-animation"/>
{{- end }}
{{- if or $showlangswitch $showthemeswitch $showvisitedlinks }}
<div id="prefooter">
<div class="footermargin footerLangSwitch footerVariantSwitch footerVisitedLinks footerFooter{{if $showlangswitch}} showLangSwitch{{end}}{{if $showvariantswitch}} showVariantSwitch{{end}}{{if $showvisitedlinks}} showVisitedLinks{{end}}{{if $showfooter}} showFooter{{end}}"></div>
<hr class="default-animation footerLangSwitch footerVariantSwitch footerVisitedLinks footerFooter{{if $showlangswitch}} showLangSwitch{{end}}{{if $showvariantswitch}} showVariantSwitch{{end}}{{if $showvisitedlinks}} showVisitedLinks{{end}}{{if $showfooter}} showFooter{{end}}"/>
<div id="prefooter" class="footerLangSwitch footerVariantSwitch footerVisitedLinks{{if $showlangswitch}} showLangSwitch{{end}}{{if $showvariantswitch}} showVariantSwitch{{end}}{{if $showvisitedlinks}} showVisitedLinks{{end}}">
<ul>
{{- if $showlangswitch }}
<li id="select-language-container">
<li id="select-language-container" class="footerLangSwitch{{if $showlangswitch}} showLangSwitch{{end}}">
<a class="padding select-container">
<i class="fas fa-language fa-fw"></i>
<span>&nbsp;</span>
<div class="select-style">
<select id="select-language" onchange="location = baseUri + this.value;">
{{- $siteLanguages := .Site.Languages }}
{{- $pageLang := .Page.Lang }}
{{- range .Page.AllTranslations }}
{{- $translation := . }}
@ -90,20 +86,18 @@
<div class="select-clear"></div>
</a>
</li>
{{- end }}
{{- if $showthemeswitch }}
<li id="select-variant-container">
<li id="select-variant-container" class="footerVariantSwitch{{if $showvariantswitch}} showVariantSwitch{{end}}">
<a class="padding select-container">
<i class="fas fa-paint-brush fa-fw"></i>
<span>&nbsp;</span>
<div class="select-style">
<select id="select-variant" onchange="variants.changeVariant( this.value );">
{{- $firsttheme := true }}
{{- $firstvariant := true }}
{{- range $themevariants }}
{{- $themevariant := . }}
{{- $variantname := replaceRE "[-_]+" " " $themevariant }}
{{- if $firsttheme }}
{{- $firsttheme = false }}
{{- if $firstvariant }}
{{- $firstvariant = false }}
<option id="{{ $themevariant }}" value="{{ $themevariant }}" selected>{{ $variantname | title }}</option>
{{- else }}
<option id="{{ $themevariant }}" value="{{ $themevariant }}">{{ $variantname | title }}</option>
@ -113,20 +107,14 @@
</div>
<div class="select-clear"></div>
</a>
<script>variants.markSelectedVariant( variants.getVariant() );</script>
<script>variants.markSelectedVariant();</script>
</li>
{{- end }}
{{- if $showvisitedlinks }}
<li><a class="padding" href="#" data-clear-history-toggle=""><i class="fas fa-history fa-fw"></i> {{ T "Clear-History" }}</a></li>
{{- end }}
<li class="footerVisitedLinks{{if $showvisitedlinks}} showVisitedLinks{{end}}"><a class="padding" href="#" data-clear-history-toggle=""><i class="fas fa-history fa-fw"></i> {{ T "Clear-History" }}</a></li>
</ul>
</div>
{{- end }}
{{- if $showfooter }}
<div id="footer">
<div id="footer" class="footerFooter{{if $showfooter}} showFooter{{end}}">
{{- $footer }}
</div>
{{- end }}
</div>
</nav>
{{- define "section-tree-nav" }}

View file

@ -5,7 +5,7 @@
<link href="{{"css/perfect-scrollbar.min.css" | relURL}}{{ if $assetBusting }}?{{ now.Unix }}{{ end }}" rel="stylesheet">
<link href="{{"css/auto-complete.css" | relURL}}{{ if $assetBusting }}?{{ now.Unix }}{{ end }}" rel="stylesheet">
<link href="{{"css/theme.css" | relURL}}{{ if $assetBusting }}?{{ now.Unix }}{{ end }}" rel="stylesheet">
{{- $themevariants := slice | append .Site.Params.themeVariant }}
{{- $themevariants := slice | append (.Site.Params.themeVariant | default "relearn-light" ) }}
{{- with index $themevariants 0 }}
<link id="variant-style" href="{{(printf "css/theme-%s.css" .) | relURL}}{{ if $assetBusting }}?{{ now.Unix }}{{ end }}" rel="stylesheet">
{{- end }}

View file

@ -1452,3 +1452,17 @@ h6 a {
display: none;
}
}
.footerLangSwitch,
.footerVariantSwitch,
.footerVisitedLinks,
.footerFooter {
display: none;
}
.showLangSwitch,
.showVariantSwitch,
.showVisitedLinks,
.showFooter {
display: initial;
}

View file

@ -3,7 +3,7 @@
var variants = {
variant: '',
variants: [],
customvariant: 'my-variant',
customvariantname: 'my-custom-variant',
init: function( variants ){
this.variants = variants;
@ -11,20 +11,11 @@ var variants = {
this.changeVariant( variant );
document.addEventListener( 'readystatechange', function(){
if( document.readyState == 'interactive' ){
this.markSelectedVariant( this.getVariant() );
this.markSelectedVariant();
}
}.bind( this ) );
},
parseVariantnameFromFilename: function ( s ){
if( !s || !s.match ){
return '';
}
var matches = s.match(/^.*\/?theme-([^\/]*?)\.css.*$/);
var variant = matches && matches.length == 2 ? matches[ 1 ] : '';
return variant;
},
getVariant: function(){
return this.variant;
},
@ -34,12 +25,14 @@ var variants = {
window.localStorage.setItem( 'variant', variant );
},
markSelectedVariant: function( variant ){
markSelectedVariant: function(){
var variant = this.getVariant();
var select = document.querySelector( '#select-variant' );
if( !select ){
return;
}
if( select.value != variant ){
this.addCustomVariantOption();
if( variant && select.value != variant ){
select.value = variant;
}
// remove selection, because if some uses an arrow navigation"
@ -50,13 +43,124 @@ var variants = {
}
},
generateVariantPath( old_path ){
var variant = this.getVariant();
generateVariantPath( variant, old_path ){
var new_path = old_path.replace( /^(.*\/theme-).*?(\.css.*)$/, '$1' + variant + '$2' );
return new_path;
},
addCustomVariantOption: function(){
var variantbase = window.localStorage.getItem( 'customvariantbase' );
if( this.variants.indexOf( variantbase ) < 0 ){
variantbase = '';
}
if( !window.localStorage.getItem( 'customvariant' ) ){
variantbase = '';
}
if( !variantbase ){
return;
}
var select = document.querySelector( '#select-variant' );
if( !select ){
return;
}
var option = document.querySelector( '#' + this.customvariantname );
if( !option ){
option = document.createElement( 'option' );
option.id = this.customvariantname;
option.value = this.customvariantname;
option.text = this.customvariantname.replace( /-/g, ' ' ).replace(/\w\S*/g, (w) => (w.replace(/^\w/g, (c) => c.toUpperCase())));
select.appendChild( option );
document.querySelectorAll( '.footerVariantSwitch' ).forEach( function( e ){
e.classList.add( 'showVariantSwitch' );
});
}
},
removeCustomVariantOption: function(){
var option = document.querySelector( '#' + this.customvariantname );
if( option ){
option.remove();
}
if( this.variants.length <= 1 ){
document.querySelectorAll( '.footerVariantSwitch' ).forEach( function( e ){
e.classList.remove( 'showVariantSwitch' );
});
}
},
saveCustomVariant: function(){
if( this.getVariant() != this.customvariantname ){
window.localStorage.setItem( 'customvariantbase', this.getVariant() );
}
window.localStorage.setItem( 'customvariant', this.generateStylesheet() );
this.setVariant( this.customvariantname );
this.markSelectedVariant();
},
loadCustomVariant: function(){
var stylesheet = window.localStorage.getItem( 'customvariant' );
// temp styles to document
var head = document.querySelector( 'head' );
var style = document.createElement( 'style' );
style.id = 'custom-variant-style';
style.appendChild( document.createTextNode( stylesheet ) );
head.appendChild( style );
var interval_id = setInterval( function(){
if( this.findLoadedStylesheet( 'variant-style' ) ){
clearInterval( interval_id );
// save the styles to the current variant stylesheet
this.variantvariables.forEach( function( e ){
this.changeColor( e.name, true );
}.bind( this ) );
// remove temp styles
style.remove();
this.saveCustomVariant();
}
}.bind( this ), 25 );
},
resetVariant: function(){
var variantbase = window.localStorage.getItem( 'customvariantbase' );
if( variantbase && confirm( 'You have made changes to your custom variant. Are you sure you want to reset all changes?' ) ){
this.removeCustomVariantOption();
this.changeVariant( variantbase );
window.localStorage.removeItem( 'customvariantbase' );
window.localStorage.removeItem( 'customvariant' );
}
},
switchStylesheet: function( variant, without_check ){
var link = document.querySelector( '#variant-style' );
if( !link ){
return;
}
var old_path = link.getAttribute( 'href' );
var new_path = this.generateVariantPath( variant, old_path );
link.setAttribute( 'href', new_path );
},
changeVariant: function( variant ){
if( variant == this.customvariantname ){
var variantbase = window.localStorage.getItem( 'customvariantbase' );
if( this.variants.indexOf( variantbase ) < 0 ){
variant = '';
}
if( !window.localStorage.getItem( 'customvariant' ) ){
variant = '';
}
this.setVariant( variant );
if( !variant ){
return;
}
this.switchStylesheet( variantbase );
this.loadCustomVariant();
}
else{
if( this.variants.indexOf( variant ) < 0 ){
variant = this.variants.length ? this.variants[ 0 ] : '';
}
@ -64,45 +168,28 @@ var variants = {
if( !variant ){
return;
}
var link = document.querySelector( '#variant-style' );
if( !link ){
return;
this.switchStylesheet( variant );
this.markSelectedVariant();
}
var old_path = link.getAttribute( 'href' );
var new_path = this.generateVariantPath( old_path );
if( old_path != new_path ){
link.setAttribute( 'href', new_path );
this.markSelectedVariant( variant );
}
},
resetVariant: function(){
var link = document.querySelector( '#variant-style' );
if( !link ){
return;
}
var old_path = link.getAttribute( 'href' );
var new_path = this.generateVariantPath( old_path );
link.setAttribute( 'href', new_path );
},
generator: function( vargenerator, vardownload, varreset ){
var graphDefinition = this.generateGraph();
var element = document.querySelector( vargenerator );
element.innerHTML = graphDefinition;
var graphs = document.querySelectorAll( vargenerator );
graphs.forEach( function( e ){ e.innerHTML = graphDefinition; });
var interval_id = setInterval( function(){
if( document.querySelectorAll( vargenerator + '.mermaid > svg' ).length ){
clearInterval( interval_id );
this.styleGraph();
}
}.bind( this ), 100 );
}.bind( this ), 25 );
var download = document.querySelector( vardownload );
download.addEventListener('click', this.getStylesheet.bind( this ) );
var downloads = document.querySelectorAll( vardownload );
downloads.forEach( function( e ){ e.addEventListener('click', this.getStylesheet.bind( this )); }.bind( this ) );
var reset = document.querySelector( varreset );
reset.addEventListener('click', this.resetVariant.bind( this ) );
var resets = document.querySelectorAll( varreset );
resets.forEach( function( e ){ e.addEventListener('click', this.resetVariant.bind( this )); }.bind( this ) );
},
download: function(data, mimetype, filename){
@ -115,7 +202,7 @@ var variants = {
},
getStylesheet: function(){
this.download( this.generateStylesheet(), 'text/css', 'theme-' + this.customvariant + '.css' );
this.download( this.generateStylesheet(), 'text/css', 'theme-' + this.customvariantname + '.css' );
},
adjustCSSRules: function(selector, props, sheets){
@ -164,11 +251,10 @@ var variants = {
return this.normalizeColor( getComputedStyle( document.documentElement ).getPropertyValue( '--INTERNAL-'+c ) );
},
changeColor: function( c ){
findLoadedStylesheet: function( id ){
var style = null;
var variant = this.variant;
for( var n = 0; n < document.styleSheets.length; ++n ){
if( variant = this.parseVariantnameFromFilename( document.styleSheets[n].href ) ){
if( document.styleSheets[n].ownerNode.id == id ){
var s = document.styleSheets[n];
for( var m = 0; m < s.rules.length; ++m ){
if( s.rules[m].selectorText == ':root' ){
@ -179,13 +265,19 @@ var variants = {
break;
}
}
if( !style ){
alert( 'Theme stylesheet for variant "' + variant + '" not set or found' );
return;
return style;
},
changeColor: function( c, without_prompt ){
without_prompt = without_prompt || false;
var read_style = this.findLoadedStylesheet( 'custom-variant-style' );
var write_style = this.findLoadedStylesheet( 'variant-style' );
if( !read_style ){
read_style = write_style;
}
var e = this.findColor( c );
var p = this.normalizeColor( style.getPropertyValue( '--'+c ) ).replace( '--INTERNAL-', '--' );
var p = this.normalizeColor( read_style.getPropertyValue( '--'+c ) ).replace( '--INTERNAL-', '--' );
var f = this.getColorValue( e.fallback );
var v = this.getColorValue( e.name );
@ -196,6 +288,11 @@ var variants = {
v = p;
}
var n = '';
if( without_prompt ){
n = v;
}
else{
var t = c + '\n\n' + e.tooltip + '\n';
if( e.fallback ){
t += '\nInherits value "' + f + '" from ' + e.fallback + ' if not set\n';
@ -203,14 +300,23 @@ var variants = {
if( e.default ){
t += '\nDefaults to value "' + this.normalizeColor(e.default) + '" if not set\n';
}
n = prompt( t, v );
}
var n = prompt( t, v );
if( n ){
n = this.normalizeColor( n ).replace( '--INTERNAL-', '--' ).replace( '--', '--INTERNAL-' );
style.setProperty( '--'+c, n );
if( without_prompt || n != v ){
write_style.setProperty( '--'+c, n );
}
if( !without_prompt ){
this.saveCustomVariant();
}
}
else if( n !== null){
style.removeProperty( '--'+c );
write_style.removeProperty( '--'+c );
if( !without_prompt ){
this.saveCustomVariant();
}
}
},
@ -239,7 +345,7 @@ var variants = {
generateStylesheet: function(){
var style =
'/* ' + this.customvariant + ' */\n' +
'/* ' + this.customvariantname + ' */\n' +
':root {\n' +
this.variantvariables.sort( function( l, r ){ return l.name.localeCompare(r.name); } ).reduce( function( a, e ){ return a + this.generateColorVariable( e ); }.bind( this ), '' ) +
'}\n';