Skip to content

[NodeBB] [JS SCRIPT/CSS] Theme Switcher

Customisation
  • Hello all,

    – I open this topic for more clarity in agreement with @phenomlab 🙂

    – Here the old topic for reference:


    Information


    – This JS and CSS script creates a button on the navbar allowing you to switch between different CSS style sheets.

    – This allows you to offer several themes to your users without going through the tedious and poorly documented bootstrap method on the NodeBB forum.

    – Note that your CSS stylesheets do not overide the code on ACP/custom CSS/ panel. They are in addition.

    alt text


    Javascript Code


    – Here is the Javascript code with comments in English and French.

    ⚠Adapt the code to your architecture (Path and files names)

    // ------------------------------------------
    // Theme Switcher
    // ------------------------------------------
    //We generate a random character string to assign a version number to the CSS file.
    // On génère une chaine de caractère aléatoire pour affecter un numéro de version au fichier CSS. 
    function generateRandomString(length) {
    
      var text = "";
      var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
    
      for (var i = 0; i < length; i++) {
          text += possible.charAt(Math.floor(Math.random() * possible.length));
      }
    
      return text;
    }
    
    $(document).ready(function ()
    {
    var string = generateRandomString(10);
    $("#random_string").text(string);
    // This variable gets the theme ID 
    // Cette variable obtient l'ID du thème
    var whichTheme = localStorage.getItem("theme");
    // This variable gets the active theme's actual URL
    //Cette variable obtient l'URL réelle du thème actif
    var activeTheme = localStorage.getItem("activeTheme");
    // This variable appends the dropdown list to the existing panel
    // Cette variable ajoute la liste déroulante au panneau existant
    var panel = $('<li id="switcher" class="dropdown text-center"> \
    <label for="theme-control-list-check" class="dropdown-toggle" data-toggle="dropdown" id="theme_dropdown" title="" role="button" data-original-title="Theme" aria-expanded="false"> \
    <a class="btn-link" title="Theme Switcher" href="#"><i id="ticon" class="fa fa-fw fa-lightbulb-o"></i><span class="visible-xs-inline">Theme Switcher</span></a> \
    </label> \
    <ul id="theme" class="dropdown-menu"> \
    <li><a id="default" href="#" rel="/assets/client.css?v=e02phpkima0">Default</a></li> \
    <li><a id="default dark" href="#" rel="/assets/customcss/default_dark.css">Default Dark</a></li> \
    <li><a id="Light Flat" href="#" rel="/assets/customcss/flat_light.css">Flat Light </a></li> \
    <li><a id="Light Flat Dark" href="#" rel="/assets/customcss/flat_dark.css">Flat Dark</a></li> \
    <li><a id="Dark Neon Aqua" href="#" rel="/assets/customcss/dark_neon_aqua.css">Dark Neon Aqua</a></li> \
    <li><a id="Dark Neon Blue" href="#" rel="/assets/customcss/dark_neon_blue.css">Dark Neon Blue</a></li> \
    <li><a id="Dark Neon Green" href="#" rel="/assets/customcss/dark_neon_green.css">Dark Neon Green</a></li> \
    <li><a id="Dark Neon Solary" href="#" rel="/assets/customcss/dark_neon_solary.css">Dark Neon Solary</a></li> \
    <li><a id="Dark Neon White" href="#" rel="/assets/customcss/dark_neon_white.css"">Dark Neon White</a></li> \
    <li><a id="Eva 00" href="#" rel="/assets/customcss/eva_00.css">Eva.00</a></li> \
    <li><a id="Eva 01" href="#" rel="/assets/customcss/eva_01.css">Eva.01</a></li> \
    <li><a id="Eva 01 Purple Green"href="#" rel="/assets/customcss/eva_01_purple_green.css">Eva.01: Purple-Green</a></li> \
    <li><a id="Eva 02" href="#" rel="/assets/customcss/eva_02.css">Eva.02: Red-Orange</a></li> \
    </ul> \
    </div> 
    ');
    
    // See if there is an active theme selected in localStorage. If none selected, use the default. If there is a theme in localStorage, use that and apply it
    // Regarde s'il y a un thème actif sélectionné dans "localStorage". Si aucun n'est sélectionné, utilise la valeur par défaut. 
    // S'il y a un thème dans localStorage, on l'utilise et on l'applique.
    if (whichTheme)
    {
    $("head").append("<link href='" + activeTheme + '?version=' + string + "' type=\"text/css\" rel=\'stylesheet\' />");
    }
    else
    {
    // No need to include anything here as there's no CSS to add.
    // Pas besoin d'inclure quoi que ce soit ici car il n'y a pas de CSS à ajouter.
    }
    
    $('ul#logged-in-menu').prepend(panel);
    $('ul#logged-out-menu').prepend(panel);
    
    if (utils.findBootstrapEnvironment() === 'xs')
    {
    $('#menu').prepend(panel);
    }
    
    $(document).ready(function () {
    // Listen to the NAV dropdown for any changes
    // Écoute la liste déroulante NAV pour tout changement de thème
    $("#theme li a").on("click change", function ()
    {
    // If we detect a change, append the selected CSS file into the DOM 
    // Si un changement est détecté, on ajoute le fichier CSS sélectionné dans le DOM (Document Object Model)
    var thishref = $(this).attr('rel');
     $("link[rel=stylesheet]").attr('href' , thishref + "?version=" + string + "");
     //location.reload();
    //$("head").append("<link href='" + $(this).attr("rel") + $(this).attr("id") + " type=\'text/css\' rel=\'stylesheet\' />");
    location.reload();
    // This variable stores the selected theme ID
    // Cette variable stocke l'ID du thème sélectionné
    var selected = $(this).attr("id");
    // This variable stores the selected theme link 
    // Cette variable stocke le lien du thème sélectionné
    var theTheme = $(this).attr("rel");
    // This variable updates the selected theme ID
    // See if "default" has been selected. If it has, then...
    // Cette variable met à jour l'ID du thème sélectionné
      // Regarde si "default" a été sélectionné. Si c'est le cas, alors...
    if (selected === 'default')
    {
    localStorage.setItem("theme", "");
    // This variable will strip the current appeneded theme ID
    // Cette variable supprimera l'ID du thème actuellement ajouté
    localStorage.setItem("activeTheme", "");
    // This variable will strip the current appeneded theme URL (HREF)
    // Finally, we have to reload the page to effect the changes
    // Cette variable supprimera l'URL actuelle du thème ajouté (HREF)
          // Enfin, on recharge la page pour effectuer les modifications
    location.reload();
    
    }
    // If any other theme is selected, carry on as normnal, and update localStorage
    // Si un autre thème est sélectionné, continuez normalement et mettez à jour localStorage
    else
    {
    localStorage.setItem("theme", selected);
    // This variable updates the actual href of the CSS file
    // Cette variable met à jour le href réel du fichier CSS
    localStorage.setItem("activeTheme", theTheme);
    //window.location.href = window.location.href
    }
    
    // We use return false to prevent the browser from reloading or following any HREF links
    // On utilise la fonction "return false" pour empêcher le navigateur de recharger ou de suivre les liens HREF
    //return false;
    });
    });
    });
    
    // When hovering over the #switcher element, target the i class and add 'themeoff'
    // Lorsque du  survol de l'élément #switcher, on cible la classe CSS "i" et on ajoute le CSS "themeoff"
    $(document).on('mouseenter','#switcher', function() {
    $('#switcher i').addClass("themeoff");
    });
    // When leaving the however state, target the i class and remove 'themeoff'
    // Lorsque l'on quitte l'état, on cible la classe CSS "i" et on supprime le CSS "themeoff"
    $(document).on('mouseleave','#switcher', function() {
    $('#switcher i').removeClass("themeoff");
    });
    

    ACP/CUSTOM CSS Code


    – Here is the CSS code to put on NodeBB ACP/CustomCSS panel.

    – It’s a base adapted to my forum, it’s up to you to adapt it to yours if certain things do not suit you.

    Code with comments with English Traduction.

    /*----------------------------------------------------------------------------*/
    /*----------------------        Themes Switcher        -----------------------*/
    /*----------------------------------------------------------------------------*/
    
     /* Works with CUSTOM JS */
    /* DON'T DELETE - DON'T MOVE */
    /* -- */
    /* Fonctionne avec du CUSTOM JS */
    /* NE PAS SUPPRIMER - NE PAS  DEPLACER */
    
    /*Desktop*/
    /*Allows to have the "Theme Switcher" icon in black after a mouse click and during the dropdown */
    /*Permet d'avoir l'icone du "Theme Switcher" en noir après un clic souris et lors du dropdown */
    [aria-expanded="true"] a #ticon {
        color: #000000;
    }
    
    /*Theme Switcher icon color via CUSTOM JAVASCRIPT */
    /* Blank without mouse over */
    /*Couleur de l'icone du Theme Switcher via le CUSTOM JAVASCRIPT */
    /* Blanc sans mouse over*/
    .themeon {
        color: #ffffff !important;
    }
    
    /*Black with mouseover*/
    /*Noir avec mouse over*/
    .themeoff {
        color: #000000 !important;
    }
    
    /*Smartphone*/
    @media all and (max-width: 1024px)
    {
    /*BUGFIX: Placement of the "Theme Switcher" */
    /*BUGFIX: Placement du "Theme Switcher" */
        #switcher {
        list-style: none;
        margin-left: -80px;
        padding-top: 15px;
    }
    
    /*BUGFIX: Space between the icon and the text "Theme Switcher" */
    /*BUGFIX: Espace entre l'icone et le texte "Theme Switcher" */
    #switcher .fa-fw {
        text-align: center;
        width: 1.25em;
        padding-right: 25px;
    }
    
    /* DON'T DELETE - DON'T MOVE */
    /*Allows to have the "Theme Switcher" icon in white after a mouse click and during the dropdown */
    /* NE PAS SUPPRIMER - NE PAS  DEPLACER */
    /*Permet d'avoir l'icone du "Theme Switcher" en blanc après un clic souris et lors du dropdown */
        [aria-expanded="true"] a #ticon {
        color: #ffffff;
    }
    
    /*Theme Switcher icon color via CUSTOM JAVASCRIPT */
    /* Blank without mouse over */
    /*Couleur de l'icone du Theme Switcher via le CUSTOM JAVASCRIPT */
    /* Blanc sans mouse over*/
        .themeoff {
        color: #ffffff !important;
    }
    }
    
    /*FIREFOX BUGFIX: Remove dotted border from icon when clicked */
    /*BUGFIX FIREFOX: Suppression de la bordure pointillée de l'icône quand on clique dessus */
    /*Desktop*/
    a:focus {
        outline:0;
    }
    
    /*Smartphone*/
    @media all and (max-width: 1024px)
    {
        a:focus {
        outline:0;
    }
    }
    
    
    /* Desktop */
    /*Button Position */
    /*Position du Bouton */
    .header #theme_dropdown {
        /*padding: 9px 15px;*/
        padding: 9px 15px; 
        padding-top: 9px;
        padding-bottom: 9px;
        margin-top: -4px;
        padding-top: 15px;
        padding-bottom: 14px;
    }
    
    /* ---- Appearance of the "Theme Switcher" icon in the navbar via Font Awesome (!!Change the CSS class also in the JS!!) ----*/
    /*Ampule*/
    /* ---- Apparence de l'icône du "Theme Switcher" dans la navbar via Font Awesome (!!Changer la class CSS aussi dans le JS!!) ----*/
    /*Ampoule*/
    .fa.fa-lightbulb-o:before {
        content: "\f0eb";
    }
    
    /*Navbar height to play with background height */
    /*Hauteur navbar pour jouer avec la hauteur du background */
    .navbar-default {
        height: 51px;
    }
    
    /*Spacing between "Search" and "Notifications" icons */
    /*Espacement entre les icônes "Recherche" et "Notifications" */
    #switcher {
        margin-top: 4px;
    }
    
    /*We remove the background on the icon */
    /*On supprime le background sur l'icone */
    #switcher .btn-link:hover {
        background: none !important;
    }
    
    /*Background color on mouseover (Default Theme) */
    /*Couleur du background au survol souris (Default Theme) */
    .navbar-default .navbar-nav>li>label:hover {
        background: #eeeeee;
    }
    
    /*Appearance of selection menu */
    /*Apparence du menu de sélection */
    #theme.dropdown-menu {
        position: absolute;
        top: 44px; 
        right: 0px;
        z-index: 1000;
        float: left;
        min-width: 160px;
        padding: 5px 0;
        margin: 2px 0 0;
        list-style: none;
        font-size: 14px;
        text-align: left;
        background-clip: padding-box;
    }
    
    /* Smartphone */
    /*Appearance of button and drop-down menu on Smartphone */
    /*Apparence du bouton et du menu déroulant sur Smartphone */
    @media all and (max-width: 1024px)
    {
        /*Dropdown menu text color */
       /*Couleur du texte du menu déroulant */
    #theme.dropdown-menu>li>a {
        display: block;
        padding: 3px 20px;
        clear: both;
        font-weight: 400;
        line-height: 1.42857143;
        color: #fff;
        white-space: nowrap;
        background: #3A3C41;
    }
    
    /*Appearance and position of button and drop-down menu */
    /*Apparence et position du bouton et du menu déroulant */
    #theme.dropdown-menu {
        position: fixed;
        top: 140px;
        left: 15px;
        z-index: 1000;
        float: left;
        min-width: 185px;
        padding: 5px 0;
        margin: 2px 0 0;
        list-style: none;
        font-size: 14px;
        text-align: left;
        /* background-clip: padding-box; */
        color: #fff;
        background: #3A3C41;
        width: 60px; /* VIOLENCE: Largeur */
        border: 1px solid black;
    }
    
    
    /*Text color and button background when selected */
    /*Couleur du texte et background du bouton lors de la selection */
    .btn-link:focus, .btn-link:hover {
        /*color: #23527c;*/
        color: lightgrey;
        text-decoration: underline;
        background-color: transparent;
    }	
    
    /*We remove the white bars at the top and bottom of the button on Smartphone */
    /*On supprime les barres blanches en haut et en bas du bouton sur Smartphone */
    .navbar-form {
        left: 20px;
        box-shadow: none;
        list-style: none;
    }
    }
    
  • DownPWundefined DownPW marked this topic as a regular topic on
  • phenomlabundefined phenomlab referenced this topic on
  • DownPWundefined DownPW referenced this topic on
  • @DownPW said in [NodeBB] [JS SCRIPT/CSS] Theme Switcher:

    ⚠Adapt the code to your architecture (Path and files names)

    How do I know the path names and files?

  • @elhana-fine

    – Firstly, you must have created your CUSTOM CSS files who correspond to your themes.

    1 CSS file = 1 theme

    – The CSS files that you will have created before with your CUSTOM CSS code inside, must be uploaded to your server in the public directory of NodeBB with subdirectory if you want or not :

    /home/YOUR_USER/PATH_TO_YOUR_NODEBB_DIRECTORY\public
    

    That path correspond to :

    https://yourdomain.com/assets
    

    And Like that, for example:

    <li><a id="default" href="#" rel="/assets/client.css?v=e02phpkima0">Default</a></li> \
    <li><a id="default dark" href="#" rel="/assets/customcss/default_dark.css">Default Dark</a></li> \
    <li><a id="Light Flat" href="#" rel="/assets/customcss/flat_light.css">Flat Light </a></li> \
    <li><a id="Light Flat Dark" href="#" rel="/assets/customcss/flat_dark.css">Flat Dark</a></li> \
    <li><a id="Dark Neon Aqua" href="#" rel="/assets/customcss/dark_neon_aqua.css">Dark Neon Aqua</a></li> \
    <li><a id="Dark Neon Blue" href="#" rel="/assets/customcss/dark_neon_blue.css">Dark Neon Blue</a></li> \
    <li><a id="Dark Neon Green" href="#" rel="/assets/customcss/dark_neon_green.css">Dark Neon Green</a></li> \
    <li><a id="Dark Neon Solary" href="#" rel="/assets/customcss/dark_neon_solary.css">Dark Neon Solary</a></li> \
    <li><a id="Dark Neon White" href="#" rel="/assets/customcss/dark_neon_white.css"">Dark Neon White</a></li> \
    <li><a id="Eva 00" href="#" rel="/assets/customcss/eva_00.css">Eva.00</a></li> \
    <li><a id="Eva 01" href="#" rel="/assets/customcss/eva_01.css">Eva.01</a></li> \
    <li><a id="Eva 01 Purple Green"href="#" rel="/assets/customcss/eva_01_purple_green.css">Eva.01: Purple-Green</a></li> \
    <li><a id="Eva 02" href="#" rel="/assets/customcss/eva_02.css">Eva.02: Red-Orange</a></li> \
    

    That why you must adapt the code of JS Script to your architecture (Path and CUSTOM CSS files names)

  • @DownPW where did this line come from ? This isn’t in the original code

    </.fal.fa-layer-group-oli>
    

    That should be just

    </li>
    
  • @phenomlab

    Exact, it’s a shell/error
    Can you delete it on the first post and my answer ?

  • @DownPW modified to reflect correct value

  • you forget first topic Mark 😉

  • Teemberlandundefined Teemberland referenced this topic on
  • Teemberlandundefined Teemberland referenced this topic on

Related Topics
  • hover link effect

    Solved Customisation
    18
    6 Votes
    18 Posts
    1k Views

    @DownPW Looking at the underlying code, class start is being added on hover by jQuery in this function

    document.querySelectorAll(".button-gradient, .button-transparent").forEach((button) => { const style = getComputedStyle(button); const lines = document.createElement("div"); lines.classList.add("lines"); const groupTop = document.createElement("div"); const groupBottom = document.createElement("div"); const svg = createSVG( button.offsetWidth, button.offsetHeight, parseInt(style.borderRadius, 10) ); groupTop.appendChild(svg); groupTop.appendChild(svg.cloneNode(true)); groupTop.appendChild(svg.cloneNode(true)); groupTop.appendChild(svg.cloneNode(true)); groupBottom.appendChild(svg.cloneNode(true)); groupBottom.appendChild(svg.cloneNode(true)); groupBottom.appendChild(svg.cloneNode(true)); groupBottom.appendChild(svg.cloneNode(true)); lines.appendChild(groupTop); lines.appendChild(groupBottom); button.appendChild(lines); button.addEventListener("pointerenter", () => { button.classList.add("start"); }); svg.addEventListener("animationend", () => { button.classList.remove("start"); }); }); })

    The CSS for start is below

    .button-gradient.start .lines svg, .button-transparent.start .lines svg { animation: stroke 0.3s linear; }

    And this is the corresponding keyframe

    @keyframes stroke { 30%, 55% { opacity: 1; } 100% { stroke-dashoffset: 5; opacity: 0; } }

    It’s using both CSS and SVG, so might not be a simple affair to replicate without the SVG files.

  • NodeBB Theme/Skin Switcher

    Solved Customisation
    38
    7 Votes
    38 Posts
    3k Views

    @Teemberland great spot ! You should create a PR for that so they can include it in the official repository.

    Just be aware that any subsequent releases will overwrite your fix without the PR.

  • 1 Votes
    2 Posts
    242 Views

    Closing this in favour of https://sudonix.com/topic/357/post-style-view/28

  • Quote design CSS

    Solved Customisation
    15
    4 Votes
    15 Posts
    1k Views

    @DownPW yes, that does make sense actually. I forgot to mention the layout of Sudonix is custom so that would have an impact on the positioning.

    Good spot 🙂

  • [NodeBB] Custom fields plugin

    Unsolved Customisation
    5
    0 Votes
    5 Posts
    906 Views

    @pwsincd hi. Just following up on this thread (I know it’s old) but was curious to understand if it’s still an issue or not ?

  • [NODEBB] Scroll Button

    Solved Customisation
    7
    0 Votes
    7 Posts
    860 Views

    @downpw ooops. Forgot that. Thanks for adding.

  • NodeBB Design help

    Solved Customisation
    8
    2 Votes
    8 Posts
    959 Views

    @riekmedia I’ve applied some new CSS to your site. Can you reload the page and try again ?

    For the record, this is what I added

    #footer { background: #2d343e; border-top: 4px solid #2d343e; font-size: 0.9em; margin-top: 70px; padding: 80px 0 0; position: relative; clear: both; bottom: 0; left: 0; right: 0; z-index: 1000; margin-left: -15px; margin-right: -338px; }

    The /categories page seems a bit messed up, so looking at that currently

    EDIT - issued some override CSS in the CATEGORIES widget

    <!--- CSS fix for overspill on /categories page - DO NOT DELETE --> <style> #footer { margin-right: -45px; } </style>

    That should resolve the /categories issue.

  • How to set a signature in NodeBB?

    Solved Customisation
    4
    2 Votes
    4 Posts
    751 Views

    @phenomlab said in How to set a signature in NodeBB?:

    @jac No issues at all with copying. This is set using the signature for the user you are posting as. In the case of Hostrisk, it’s set like the below

    7bf04183-f6e8-4d72-b0eb-c9a05c9cd24b-image.png

    You can set the signature by using https://domain.com/user/theuser/edit

    Mamy thanks Mark, I’ll set this up later 😁.