Full solution to Dynamic color scheme + extras



  • The following two SCSS mixins I need to use in Quasar Framework in Stylus:

    Once I found out how to rewrite these in Stylus I’ll post here so it can be useful for others as well!



  • @mesqueeb First mixin:

    strip-unit($value)
      unit($value, '')
    
    fluid-type($properties, $min-vw, $max-vw, $min-value, $max-value)
      for $property in $properties
        {$property}: $min-value
    
      @media screen and (min-width: $min-vw)
        for $property in $properties
          {$property}: s('calc(%s + %s * (100vw - %s) / %s)', $min-value, strip-unit($max-value - $min-value), $min-vw, strip-unit($max-vw - $min-vw))
    
      @media screen and (min-width: $max-vw)
        for $property in $properties
          {$property}: $max-value
    
    /* Single property */
    html
      fluid-type(font-size, 320px, 1366px, 14px, 18px)
    
    /* Multiple properties with same values */
    h1
      fluid-type(padding-bottom padding-top, 20em, 70em, 2em, 4em)
    


  • @leopiccionia WOW!!! Thanks so much!!



  • @mesqueeb The following is functionally equivalent to second mixin, if I understood it correctly. If you’re curious, @(...){...} defines an anonymous mixin (much like an anonymous function). The second parameter can be either a named mixin or, in the following case, an anonymous mixin:

    $themes = {
      "theme-1": {
        "color": red
      },
      "theme-2": {
        "color": orange
      },
      "theme-3": {
        "color": yellow
      },
      "theme-4": {
        "color": green
      },
      "theme-5": {
        "color": blue
      }
    }
    
    themify($themes, $mixin)
      for $theme in $themes
        .{$theme} &
          $mixin($themes[$theme])
    
    .test
      themify($themes, @($theme) {
        color: $theme.color
      })
    


  • Uhm, I don’t know why the Stylus code is not being syntax-highlighted.



  • This post is deleted!


  • Wow. @leopiccionia you are a Stylus pro!!! You have just solved so many people’s problems trying to have dynamic theming!



  • Although I prefer Stylus, I’m actually more used to SCSS (which I use on my job). I used the Stylus compiler (a NPM package!) and trial-and-error approach. Some features, like anonymous and high-order functions/mixins, were actually great surprises, as I haven’t used them before in Stylus.



  • @leopiccionia I was able to successfully integrate it into my stylus files.

    The very cool thing you can do with this. You know Quasar has a lot of components where you can e.g. color="primary.
    Now if I include a styl file like so:

    .text-primary
      themify($themes, @($theme) {
        color: $theme.$primary !important
      })
    .bg-primary
      themify($themes, @($theme) {
        background: $theme.$primary !important
      })
    

    And you have a primary color setup for another theme e.g. theme-retro. Then just by adding the class theme-retro to the body tag all component’s primary color will change into your new theme!
    Isn’t that cool? : )

    You’d need to setup the retro theme like so:

    $themes = {
      "theme-retro": {
        "$primary": purple
      },
    }
    

    Now the final question: Do you think it’s possible to wrap it into another mixin to make using the mixin less verbose?
    Cheers!



  • Full example:

    The variables in a styl file:

    $themes = {
      "theme-default": {
        '$primary': $primary
        '$secondary': $secondary
        '$tertiary': $tertiary
    
        '$neutral': $neutral
        '$positive': $positive
        '$negative': $negative
        '$info': $info
        '$warning': $warning
    
        '$light': $light
        '$dark': $dark
      },
      "theme-retro": {
        '$primary': purple
        '$secondary': lime
        '$tertiary': grey
    
        '$neutral': $neutral
        '$positive': $positive
        '$negative': $negative
        '$info': $info
        '$warning': $warning
    
        '$light': $dark
        '$dark': $light
      },
    }
    // Create the Stylus mixin:
    themify($themes, $mixin)
      for $theme in $themes
        .{$theme} &
          $mixin($themes[$theme])
    

    You can see that the themes hold the original values from Quasar. To change these you best change them before you make your $themes object.
    Then in the theme-retro you see I can leave original options or change to my second theme. I can even switch around light and dark!

    Then you have to add all the Quasar color classes with the correct mixin like so:

    
    .text-primary
      themify($themes, @($theme) {
        color: $theme.$primary !important
      })
    
    .bg-primary
      themify($themes, @($theme) {
        background: $theme.$primary !important
      })
    
    .text-secondary
      themify($themes, @($theme) {
        color: $theme.$secondary !important
      })
    .bg-secondary
      themify($themes, @($theme) {
        background: $theme.$secondary !important
      })
    
    .text-tertiary
      themify($themes, @($theme) {
        color: $theme.$tertiary !important
      })
    .bg-tertiary
      themify($themes, @($theme) {
        background: $theme.$tertiary !important
      })
    
    .text-faded
      themify($themes, @($theme) {
        color: $theme.$faded !important
      })
    .bg-faded
      themify($themes, @($theme) {
        background: $theme.$faded !important
      })
    
    .text-positive
      themify($themes, @($theme) {
        color: $theme.$positive !important
      })
    .bg-positive
      themify($themes, @($theme) {
        background: $theme.$positive !important
      })
    
    .text-negative
      themify($themes, @($theme) {
        color: $theme.$negative !important
      })
    .bg-negative
      themify($themes, @($theme) {
        background: $theme.$negative !important
      })
    
    .text-info
      themify($themes, @($theme) {
        color: $theme.$info !important
      })
    .bg-info
      themify($themes, @($theme) {
        background: $theme.$info !important
      })
    
    .text-warning
      themify($themes, @($theme) {
        color: $theme.$warning !important
      })
    .bg-warning
      themify($themes, @($theme) {
        background: $theme.$warning !important
      })
    
    .text-light
      themify($themes, @($theme) {
        color: $theme.$light !important
      })
    .bg-light
      themify($themes, @($theme) {
        background: $theme.$light !important
      })
    
    .text-dark
      themify($themes, @($theme) {
        color: $theme.$dark !important
      })
    .bg-dark
      themify($themes, @($theme) {
        background: $theme.$dark !important
      })
    

    That’s all! Now your Quasar components will change when you change a class on the <body> tag from theme-default to theme-retro.



  • @mesqueeb You could obviously wrap themify inside another mixin, but I don’t think it’s a scalable solution, as you’d need to know the keys ($primary, $secondary) a priori, and maintain a value to each key in each theme.

    I’d rather pass a mixin to themify that infer the color keys from the theme itself.

    themify-palette($theme)
      for $k, $v in $theme
        $k-stripped = match('^\$(.*)', $k)[1]
        & .bg-{$k-stripped}
          background-color: $v !important
        & .text-{$k-stripped}
          color: $v !important
    
    themify($themes, themify-palette)
    

    As a side note, I’d say something like this is more readable:

    $themes = {
      'theme-default': {
        'colors': {
          'primary': $primary
          'secondary': $secondary
          'tertiary': $tertiary
    
          'neutral': $neutral
          'positive': $positive
          'negative': $negative
          'info': $info
          'warning': $warning
    
          'light': $light
          'dark': $dark
        },
      },
      'theme-retro': {
        'colors': {
          'primary': purple
          'secondary': lime
          'tertiary': grey
    
          'neutral': $neutral
          'positive': $positive
          'negative': $negative
          'info': $info
          'warning': $warning
    
          'light': $dark
          'dark': $light
        },
      },
    }
    
    themify($themes, $mixin)
      for $theme in $themes
        .{$theme} &
          $mixin($themes[$theme])
    
    themify-palette($theme)
      for $k, $v in $theme.colors
        & .bg-{$k}
          background-color: $v !important
        & .text-{$k}
          color: $v !important
    
    themify($themes, themify-palette)
    

  • Admin

    Dynamic branding colors - configurable at any time during runtime in 0.15.7 already – to be released in less than 24 hours.



  • @rstoenescu Did I inspire you to add this?! : D
    Can’t wait!!



  • @leopiccionia
    The first mixin with the fluid font-size etc. Is it possible that it doesn’t work well with setting some height to vh?

    .o-hero-carousel
      fluid-type(height, $breakpoint-xs, $breakpoint-lg, 50vh, 80vh)
    

    I tried this but the calculation seems to be a little bit off. Can I use anything besides px? (what about rem and em?)



  • @mesqueeb

    The first mixin with the fluid font-size etc. Is it possible that it doesn’t work well with setting some height to vh?

    Your problem may be related to an issue where some browsers doesn’t allow vh and vw values inside calc() expressions.

    (what about rem and em?)

    It should work as expected, as my mixin and the one you provided in Sass should output the same on a demo using em. If the outputs are different, let me know.


  • Admin



  • @rstoenescu how to dynamically change the theme of an app
    according to user ?any tutorial please suggest