UNPKG

bootswatch-sass

Version:

Bootswatch is a collection of themes for Bootstrap. SASS / SCSS edition

248 lines (225 loc) 10.2 kB
module.exports = function (grunt) { grunt.loadNpmTasks('grunt-contrib-sass'); grunt.loadNpmTasks('grunt-contrib-concat'); grunt.loadNpmTasks('grunt-contrib-connect'); grunt.loadNpmTasks('grunt-contrib-clean'); grunt.loadNpmTasks('grunt-contrib-watch'); grunt.loadNpmTasks('grunt-patch'); grunt.loadNpmTasks("grunt-update-submodules"); grunt.loadNpmTasks('grunt-git'); // Project configuration. grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), builddir: '.', buildtheme: '', banner: '/*!\n' + ' * <%= pkg.name %> v<%= pkg.version %>\n' + ' * Homepage: <%= pkg.homepage %>\n' + ' * Copyright 2012-<%= grunt.template.today("yyyy") %> <%= pkg.author %>\n' + ' * Licensed under <%= pkg.license %>\n' + ' * Based on Bootstrap\n' + '*/\n', swatch: { amelia: {}, cerulean: {}, cosmo: {}, cyborg: {}, darkly: {}, flatly: {}, journal: {}, lumen: {}, paper: {}, readable: {}, sandstone: {}, simplex: {}, slate: {}, spacelab: {}, superhero: {}, united: {}, yeti: {}, custom: {} }, clean: { build: { src: ['*/build.scss', '!global/build.scss'] } }, concat: { options: { banner: '<%= banner %>', stripBanners: false }, dist: { src: [], dest: '' } }, sass: { dist: { options: { style: 'nested' }, files: {} } }, watch: { files: ['*/variables.scss', '*/bootswatch.scss', '*/index.html'], tasks: 'build', options: { livereload: true, nospawn: true } }, connect: { base: { options: { port: 3000, livereload: true, open: true } }, keepalive: { options: { port: 3000, livereload: true, keepalive: true, open: true } } }, convert_less: {}, apply_patch: {}, update_submodules: { withCustomParameters: { options: { params: "--init --recursive --force" // specifies your own command-line parameters } } } }); grunt.registerTask('none', function () { }); grunt.registerTask('build', 'build a regular theme', function (theme, compress) { var theme = theme == undefined ? grunt.config('buildtheme') : theme; var compress = compress == undefined ? true : compress; var isValidTheme = grunt.file.exists(theme, '_variables.scss') && grunt.file.exists(theme, '_bootswatch.scss'); // cancel the build (without failing) if this directory is not a valid theme if (!isValidTheme) { return; } var concatSrc; var concatDest; var scssDest; var scssSrc; var files = {}; var dist = {}; concatSrc = 'global/build.scss'; concatDest = theme + '/build.scss'; scssDest = '<%=builddir%>/' + theme + '/bootstrap.css'; scssSrc = [theme + '/' + 'build.scss']; dist = {src: concatSrc, dest: concatDest}; grunt.config('concat.dist', dist); files = {}; files[scssDest] = scssSrc; grunt.config('sass.dist.files', files); grunt.config('sass.dist.options.style', 'nested'); grunt.task.run(['concat', 'sass:dist', 'clean:build', compress ? 'compress:' + scssDest + ':' + '<%=builddir%>/' + theme + '/bootstrap.min.css' : 'none']); }); grunt.registerTask('compress', 'compress a generic css', function (fileSrc, fileDst) { var files = {}; files[fileDst] = fileSrc; grunt.log.writeln('compressing file ' + fileSrc); grunt.config('sass.dist.files', files); grunt.config('sass.dist.options.style', 'nested'); grunt.task.run(['sass:dist']); }); grunt.registerMultiTask('swatch', 'build a theme', function () { var t = this.target; grunt.task.run('build:' + t); }); /** * Regex borrowed form * https://gist.github.com/rosskevin/ddfe895091de2ca5f931 * */ grunt.registerTask('convert_less', 'naively convert less to scss (may require some debugging)', function () { var convertBaseDir = 'bootswatch/'; grunt.file.expand(convertBaseDir + '*/*.less').forEach(function (f) { var srcContents = grunt.file.read(f); var out = srcContents // 1. replace @ with $ .replace(/@(?!import|media|keyframes|-)/g, '$') // 2. replace mixins .replace(/[\.#](?![0-9])([\w\-]*)\s*\((.*)\)\s*\{/g, '@mixin $1($2){') // 3. In LESS, bootstrap namespaces mixins, in SASS they are just prefixed e.g #gradient > .vertical-three-colors becomes @include gradient-vertical-three-colors .replace(/[\.#](?![0-9])([\w\-]*)\s>\s\.(.*;)/g, '@include $1-$2') // 4. replace includes .replace(/[\.#](?![0-9])([\w\-].*\(.*;)/g, '@include $1') // 5. replace no param mixin includes with empty parens .replace(/@include\s([\w\-]*\s*);/g, '@include $1();') // 6. replace string literals .replace(/~"(.*)"/g, '#{"$1"}') // 7. replace spin to adjust-hue (function name diff) .replace(/spin\(/g, 'adjust-hue(') // 8. replace bower and imports in build.scss .replace(/bootstrap\/less\//g, 'bootstrap-sass-official/assets/stylesheets/') .replace(/\.less/g, ''); var baseDirRegex = new RegExp("^" + convertBaseDir, "g"); var dest = f.replace(baseDirRegex, '').replace(/\.less$/, '.scss').replace(/(bootswatch|variables)/, '_$1'); grunt.file.write(dest, out); grunt.log.writeln('Converted less file:', f, dest); var patchFile = dest.replace(/\.scss$/, '.scss.patch'); if (grunt.file.exists(patchFile)) { grunt.log.writeln(' Found patch:', patchFile); grunt.task.run(['apply_patch:' + patchFile + ':' + dest]); } if (out.match(/\$\$/g)) { grunt.log.warn("This file may contain illegal variable references that will have to be manually refactored", f); var howto = ""; grunt.log.warn(howto); } }); }); grunt.registerTask('update_html', 'Update html files replace less references with sass', function () { var convertBaseDir = 'bootswatch/'; var htmlFiles = grunt.file.expand(convertBaseDir + '*/*.html'); htmlFiles.push(convertBaseDir+"index.html"); htmlFiles.forEach(function (f) { var srcContents = grunt.file.read(f); var out = srcContents .replace(/(.*user=)thomaspark(&repo=)bootswatch(.*)/g, '$1guru-digital$2bootswatch-sass$3') .replace(/(github.com)\/thomaspark\/bootswatch(.*)/g, '$1/guru-digital/bootswatch-sass$2') .replace(/LESS/g, 'SCSS') .replace(/(bootswatch|variables)\.less/g, '_$1.scss'); var baseDirRegex = new RegExp("^" + convertBaseDir, "g"); var dest = f.replace(baseDirRegex, ''); grunt.file.write(dest, out); grunt.log.writeln('Parsed HTML file:', f, dest); var patchFile = dest+'.patch'; if (grunt.file.exists(patchFile)) { grunt.log.writeln(' Found patch:', patchFile); grunt.task.run(['apply_patch:' + patchFile + ':' + dest]); } }); }); grunt.registerTask('update_bootswatch_less', 'Update the less version submodule', function (patchFile, dest) { grunt.task.run(['update_submodules']); var cwd = process.cwd(); grunt.file.setBase(cwd + "/bootswatch"); grunt.config('gitpull.bootswatch.options.remote', 'origin'); grunt.config('gitpull.bootswatch.options.branch', 'gh-pages'); grunt.task.run(['gitpull']); grunt.file.setBase(cwd); }); grunt.registerTask('sync_with_upstream', 'Update bootswatch sass from the original bootswatch', function (patchFile, dest) { grunt.task.run(['update_bootswatch_less', 'convert_less', 'update_html', 'swatch']); }); grunt.registerTask('create_patch', 'Creates a patch file', function (oldFile, newFile) { var jsdiff = require('diff'); var patchFile = oldFile + ".patch"; var newText = grunt.file.read(newFile); var oldText = grunt.file.read(oldFile); var diffText = jsdiff.createPatch(patchFile, oldText, newText); grunt.file.write(patchFile, diffText); }); grunt.registerTask('apply_patch', 'apply a unified patch file', function (patchFile, dest) { var files = {}; files[dest] = dest; grunt.config('patch.dist.options.patch', patchFile); grunt.config('patch.dist.files', files); grunt.task.run(['patch:dist']); }); grunt.event.on('watch', function (action, filepath) { var path = require('path'); var theme = path.dirname(filepath); grunt.config('buildtheme', theme); }); grunt.registerTask('server', 'connect:keepalive'); grunt.registerTask('default', ['connect:base', 'watch']); };