2

I have a scss variable $tint-color that is used in about 100 places.

Once the user logs in, I would like to load a color based on their profile and replace all the usages of $tint-color.

So far I have found two non-ideal solutions:

1) Iterate through all elements and replace the relevant properties.

I am constantly generating new elements -- so this would need to happen repeatedly.

2) Create an override stylesheet, that targets each element.

This will require a lot of duplicate code.

Is there a better / simpler way? I have thought about adding a class to an element in scss, but I am not sure this is possible. Thank you for your help in advance!

Community
  • 1
  • 1
jonperl
  • 871
  • 1
  • 10
  • 22

2 Answers2

2

What I am doing now, is loading a theme css file after the profile is loaded.

On the server I expose an iron-router route that dynamically replaces any occurrence of the color and returns the theme css.

The issue is that I am not replacing the scss variables, instead I am replacing any occurrence of the color. This is because when the code is executed the .scss files have already been bundled into a .css file on the server.

// return a theme based on the tintColor parameter
this.route('theme', {
    where: 'server',

    action: function () {
        var files = fs.readdirSync('../client');

        // find the css file (not the .map file)
        var cssFile = _(files).find(function (fileName) {
            return fileName.indexOf('.css') > 0 && fileName.indexOf('.map') < 0;
        });

        var style = fs.readFileSync('../client/' + cssFile, 'utf8');

        // remove comments (cannot have them for minification)
        style = style.replace(/(?:\/\*(?:[\s\S]*?)\*\/)|(?:([\s;])+\/\/(?:.*)$)/gm, '');

        // replace the default tint-color with the dynamic color
        style = style.replace(/8cb850/g, this.params.tintColor);

        // minify css
        if (Settings.isProduction()) {
            // from the minifiers package
            style = CssTools.minifyCss(style);
        }

        this.response.writeHead(200, {'Content-Type': 'text/css'});
        this.response.end(style);
    }
});

Update: I got it to generate with scss variables.

Theme.compile = function (tintColor) {
    var dirName = path.dirname(styleFile);

    var styles = fs.readFileSync(styleFile, 'utf8');

    //replace default theme with dynamic theme
    var theme = '$tint-color: #' + tintColor + ';' + '\n';
    styles = styles.replace('@import "app/theme.scssimport";', theme);

    var options = {
        data: styles,
        sourceComments: 'map',
        includePaths: [dirName] // for @import
    };

    var css = sass.renderSync(options);

    // minify css
    if (Settings.isProduction()) {
        // remove comments -- cannot have them for minification
        css = css.replace(/(?:\/\*(?:[\s\S]*?)\*\/)|(?:([\s;])+\/\/(?:.*)$)/gm, '');

        // Use CssTools from the minifiers package
        css = CssTools.minifyCss(css);
    }

    return css;
};

If you do this make sure you add the scss files as assets in the package, example here.

jonperl
  • 871
  • 1
  • 10
  • 22
1

Set a basic $tint-color in your original css.

Then use meteor to send inline CSS with the selected user-tint.

Example:

.tint {
  background-color: USER-TINT;
  color: USER-TINT;
}

That way you can cache the original css file and save loads of transfer!

albinekb
  • 194
  • 4
  • Are you recommending to generate an override stylesheet on the server? – jonperl Apr 16 '14 at 15:40
  • @jonperl, yes and no. You should always try to keep the number of files to a minimum. In this case i would either use JS to inject the needed custom CSS colors, or use meteors excellent Template engine to render the custom styles. That way you can update it on-the-go if needed, without needing to send the whole generated stylesheet to the client. I hope this cleared things out, I'm not the best at explaining stuff! Feel free to contact me if you want to discuss it further! – albinekb Apr 21 '14 at 08:08
  • Thanks for the further explanation. The problem with this approach, is that I use the tint-color in ~ 30% of the selectors. This would require a TON of template specific logic, which for code complexity I would prefer to avoid. Since the css will be cached after the first download, I am not too concerned about the first initial overhead. – jonperl Apr 23 '14 at 15:28