Grunt plugin for building living styleguides with Handlebars from Markdown comments in CSS, SASS and LESS files.
Note: This plugin is in semi-active development! So expect it to be a little rough around the edges. If you have any questions, issues or suggestions get in touch. Currently on version 0.2.7
.
- Path resolving is relative; no more issues serving from localhost or using file:// protocols
- Whitespace and preformatting is preserved in markup results
- Source styles shown in conjunction with markup and result
- Pages are served form an array-literal node tree; meaning clearer and nested navigation
- Comment block matching is modifiable via regular expressions
- Choice of syntax highlighting styles from various popular Highlight.js themes
- Syntax highlighting is done with Node before templates compile; faster page loads
Install this plugin with this command:
npm install sassdown --save-dev
Enabled inside your Gruntfile with this line of JavaScript:
grunt.loadNpmTasks('sassdown');
Run the task using grunt sassdown
. Task targets, files and options may be specified according to the grunt configuring tasks guide.
In your project's Gruntfile, add a section named sassdown
to the data object passed into grunt.initConfig()
.
sassdown: {
options: {
// Task-specific options go here.
},
target: {
// Target-specific file lists and/or options go here.
},
},
Type: Array
Default: null
Optional. Array of file paths. Will be included into the styleguide output. Supports globbing. Supports relative and absolute file paths (eg. http://
, https://
, //
or even file://
).
Type: String
Default: null
Optional. A path to a Handlebars template file. Will use default Sassdown template if left blank.
Type: Array
Default: null
Optional. Array of file paths. The Handlebars helpers will be available to use in the template. Supports globbing. Supports relative and absolute file paths (eg. http://
, https://
or even file://
).
Type: String
Default: null
Optional. A path to a theme stylesheet. Will use default Sassdown theme if left blank.
Type: String
Default: null
Optional. Path to a README file. When set, this file will be parsed with Markdown and used as the index page for the styleguide.
Type: String
Default: github
Optional. Choice of syntax highlighting style. Defaults to github
, but other available options are: docco
, monokai
, solarized-light
, solarized-dark
or xcode
.
Type: Array
Default: null
Optional. Array of file paths. The scripts will be linked with script tags with src attributes. Supports globbing. Supports relative and absolute file paths (eg. http://
, https://
, //
or even file://
).
If this option is set the default scripts won't be included, but you can include them again by adding node_modules/sassdown/tasks/data/scripts.js
to the file list, or by copying and modifying that file.
Type: RegExp
Default: /\/\*/
Optional. A regular expression to match beginning part of a comment block. Defaults to regular block comment (/*
).
Type: RegExp
Default: /\*\//
Optional. A regular expression to match ending part of a comment block. Defaults to regular block comment (*/
).
Type: Boolean
Default: false
Optional. When set to true, Sassdown will ignore any files that do not contain matching or valid comment blocks.
Type: Boolean
Default: false
Optional. When set to true, Sassdown will not generate any files, and will exit with status 1
if any files do not contain matching or valid comment blocks.
You will need to use an expanded files object, but here is roughly the minimum configuration required.
sassdown: {
styleguide: {
options: {
assets: ['public/css/*.css']
},
files: [{
expand: true,
cwd: 'src/sass',
src: ['*.scss'],
dest: 'public/styleguide/'
}]
}
},
On larger projects you may need to include additional assets and customise the output with a user theme, template and scripts.
sassdown: {
styleguide: {
options: {
assets: [
'public/css/**/*.min.css',
'public/js/*.min.js',
'http://use.typekit.net/sea5yvm.js',
],
theme: 'src/styleguide/theme.css',
template: 'src/styleguide/template.hbs',
scripts: ['src/styleguide/*.js'],
readme: 'src/assets/sass/readme.md',
highlight: 'monokai',
excludeMissing: true
},
files: [{
expand: true,
cwd: 'src/assets/sass',
src: [
'partials/**/*.{scss,sass}',
'modules/**/*.{scss,sass}'
],
dest: 'public/styleguide/'
}]
}
},
Sassdown uses Markdown to parse any block comments in your SASS files. From these, it generates the text content in the styleguide. Any recognised code blocks will be rendered as HTML/SCSS source-result pairs.
You may use any Markdown-compatible heading syntax you like. You may use any common style of block-comment syntax you like. Code blocks may be fenced or indented (four spaces). Below are several examples; each will be correctly parsed by Sassdown into identical output.
/*
Alerts
======
Creates an alert box notification using the `.alert-` prefix. The following options are available:
<div class="alert-success">Success</div>
<div class="alert-warning">Warning</div>
<div class="alert-error">Error</div>
*/
@mixin alert($colour){
color: darken($colour, 50%);
background: $colour;
border-radius: 5px;
margin-bottom: 1em;
padding: 1em;
}
.alert-success { @include alert(#e2f3c1) }
.alert-warning { @include alert(#fceabe) }
.alert-error { @include alert(#ffdcdc) }
Handlebars is a semantic templating syntax. Put simply, it allows you to output dynamic properties in HTML using {{var}}
from a variety of data sources such as JSON.
Sassdown uses Handlebars to output data from the data objects it creates. Your .hbs
file specified in the template
option may contain code that looks like this for example:
{{#each page.sections}}
<div class="section">
{{#if comment}}
<div class="comment">{{{comment}}}</div>
{{/if}}
{{#if result}}
<div class="result">{{{result}}}</div>
{{/if}}
{{#if markup}}
<div class="markup">{{{markup}}}</div>
{{/if}}
{{#if styles}}
<div class="styles">{{{styles}}}</div>
{{/if}}
</div>
{{/each}}
Sassdown also provides a series of Handlebars partials, which can be used to output specific information on each page. These are:
-
{{> root}}
Outputs a path to the root directory of the styleguide, relative to whatever page you are on. -
{{> assets}}
Outputs a set of<link />
or<script>
tags that include assets specified in the Grunt task options. -
{{> theme}}
Outputs the theme stylesheet, minified, into a<style>
tag.
You can add more features to Handlebar templates by using Helpers.
For example you could add a helper that capitalizes all text:
<big>{{uppercase shoutThis}}</big>
You load your helpers with the handlebarsHelpers
option.
handlebarsHelpers: ['hb-helpers/**/*.js']
The helper module must export a function that does the registration, or else it won't load.
module.exports = function(Handlebars) {
Handlebars.registerHelper('uppercase', function(input) {
return typeof input === 'string' ? input.toUpperCase() : input;
});
};
// This also works
module.exports = {
register: function(Handlebars) {
...
}
Sassdown uses the popular and well-supported Highlight.js for syntax highlighting. Markup is parsed by a Node module and highlighted before being output through the template. Various popular themes are supported via the task options.
Two objects are parsed into the Handlebars template; Page
and Pages
. Page contains json data for the current page only; Pages is an array literal containing all Page objects in a nested node tree.
Any property within these objects can be output by Handlebars using {{helpers}}
. You can iterate through objects using {{#each}} ... {{/each}}
, for example.
{
title: 'Alerts',
slug: '_alerts',
href: 'objects/user/_alerts.html',
dest: 'test/example/styleguide/objects/user/_alerts.html',
src: 'test/example/assets/sass/partials/objects/user/_alerts.scss',
sections: [
{
id: 'mswbu',
comment: '<h1 id="alerts">Alerts</h1>\n<p>Creates an alert box notification using the <code>.alert-</code> prefix. The following options are available:</p>\n',
result: '\n<div class="alert-success">Success</div> \n<div class="alert-warning">Warning</div> \n<div class="alert-error">Error</div>\n',
markup: '<pre><code><span class="token tag" ><span class="token tag" ><span class="token punctuation" ><</span>div</span> <span class="token attr-name" >class</span><span class="token attr-value" ><span class="token punctuation" >=</span>"alert-success"></span></span>Success<span class="token tag" ><span class="token tag" ><span class="token punctuation" ></</span>div</span><span class="token punctuation" >></span></span> \n<span class="token tag" ><span class="token tag" ><span class="token punctuation" ><</span>div</span> <span class="token attr-name" >class</span><span class="token attr-value" ><span class="token punctuation" >=</span>"alert-warning"></span></span>Warning<span class="token tag" ><span class="token tag" ><span class="token punctuation" ></</span>div</span><span class="token punctuation" >></span></span> \n<span class="token tag" ><span class="token tag" ><span class="token punctuation" ><</span>div</span> <span class="token attr-name" >class</span><span class="token attr-value" ><span class="token punctuation" >=</span>"alert-error"></span></span>Error<span class="token tag" ><span class="token tag" ><span class="token punctuation" ></</span>div</span><span class="token punctuation" >></span></span></code></pre>\n',
styles: '<pre><code><span class="token keyword" >@mixin</span> alert(<span class="token variable" >$colour</span>)<span class="token punctuation" >{</span>\n <span class="token property" >color</span><span class="token punctuation" >:</span> darken(<span class="token variable" >$colour</span>, 50%)<span class="token punctuation" >;</span>\n <span class="token property" >background</span><span class="token punctuation" >:</span> <span class="token variable" >$colour</span><span class="token punctuation" >;</span>\n <span class="token property" >border-radius</span><span class="token punctuation" >:</span> 5px<span class="token punctuation" >;</span>\n <span class="token property" >margin-bottom</span><span class="token punctuation" >:</span> 1em<span class="token punctuation" >;</span>\n <span class="token property" >padding</span><span class="token punctuation" >:</span> 1em<span class="token punctuation" >;</span>\n<span class="token punctuation" >}</span>\n\n.alert-success <span class="token punctuation" >{</span> <span class="token keyword" >@include</span> alert(#e2f3c1) <span class="token punctuation" >}</span>\n.alert-warning <span class="token punctuation" >{</span> <span class="token keyword" >@include</span> alert(#fceabe) <span class="token punctuation" >}</span>\n.alert-error <span class="token punctuation" >{</span> <span class="token keyword" >@include</span> alert(#ffdcdc) <span class="token punctuation" >}</span></code></pre>\n'
}
]
}
[
{
name: 'base',
isDirectory: true,
pages: [
[Object],
{
name: 'typography',
isDirectory: true,
pages: [
[Object],
[Object],
[Object]
]
},
[Object],
[Object]
]
},
{
name: 'partials',
isDirectory: true,
pages: [
[Object],
[Object]
]
},
{
name: 'modules',
isDirectory: true,
pages: [
[Object]
]
},
{
name: 'objects',
isDirectory: true,
pages: [
[Object],
[Object],
[Object]
]
}
]
Should you wish to create a new Sassdown template, you may wish to use the existing default template.hbs as a base to work from.
It should be noted that, despite the name, Sassdown does not explicitly read only SASS files. It works just fine with .sass, .less, .css or even .txt files.
Sassdown does not compile your source files. Assuming you are using SASS, and since you're using Grunt, I would recommend the grunt-contrib-compass plugin for this task. However you may also want to look at grunt-contrib-stylus.
Current milestones for this project
- Fork it
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request