├── .gitattributes ├── .gitignore ├── .npmignore ├── .travis.yml ├── README.md ├── assets ├── favicons │ └── favicon-32x32.png └── js │ └── cl.js ├── demo ├── assets │ ├── project.css │ └── project.js ├── gulpfile.js ├── public │ └── index.html └── src │ ├── layout.html │ └── templates │ ├── 0.intro.html │ ├── 1.foundation │ ├── 1.Colors │ │ ├── 1.palette.html │ │ ├── 3.color-classes.html │ │ └── 4.background-utilities.html │ ├── 2.Grid │ │ └── simple-grid.html │ ├── Addresses.html │ ├── Alerts.html │ ├── Badges.html │ ├── Buttons │ │ ├── 1.basic.html │ │ ├── button-groups.html │ │ ├── justified.html │ │ ├── vertical.html │ │ └── with-dropdowns.html │ ├── Definition Lists │ │ ├── 1.vertical.html │ │ └── 2.horizontal.html │ ├── Dropdowns.html │ ├── Forms │ │ ├── 1.basic-example.html │ │ ├── 2.inline-form.html │ │ └── 3.horizontal-form.html │ ├── Images.html │ ├── Labels.html │ ├── Tables.html │ ├── Typography │ │ ├── 1.blockquote.html │ │ ├── 2.blockquote-reverse.html │ │ ├── Emphasis │ │ │ ├── bold-text.html │ │ │ ├── italics-text.html │ │ │ └── small-text.html │ │ ├── Lists │ │ │ ├── list-inline.html │ │ │ ├── list-ordered.html │ │ │ ├── list-unordered.html │ │ │ └── list-unstyled.html │ │ ├── body-copy.html │ │ ├── headings.html │ │ ├── lead-copy.html │ │ ├── links.html │ │ └── text-alignment.html │ ├── Well.html │ └── icons.html │ └── 2.components │ ├── Media Objects │ ├── default.html │ └── list.html │ ├── Navigation │ ├── 1.Navbar.html │ ├── 2.Tabs.html │ ├── 3.Justified-Tabs.html │ ├── 4.Pills.html │ ├── 5.Stacked-Pills.html │ └── 6.Dropdown-Tabs.html │ ├── Pagination │ ├── 1.default.html │ ├── 2.large.html │ └── 3.small.html │ ├── breadcrumbs.html │ ├── list-groups.html │ ├── pager.html │ ├── progress-bars.html │ └── thumbnails.html ├── package.json ├── sass ├── _components.scss ├── _init.scss ├── _tree.scss ├── bootstrap │ ├── _theme.scss │ └── _variables.scss ├── cl.scss └── components │ ├── _icon-list.scss │ └── _palette.scss └── src ├── assemblers ├── __tests__ │ ├── assets.test.js │ ├── assets │ │ └── input │ │ │ ├── folder │ │ │ └── another-asset.txt │ │ │ └── test-asset.txt │ ├── sass.test.js │ ├── sass │ │ └── input │ │ │ ├── bad.scss │ │ │ └── good.scss │ ├── templates.test.js │ └── templates │ │ └── input │ │ ├── 1.atoms │ │ ├── 1.Colors │ │ │ ├── 1.palette.html │ │ │ ├── 3.color-classes.html │ │ │ └── 4.background-utilities.html │ │ └── alerts.html │ │ ├── 2.molecules │ │ ├── breadcrumbs.html │ │ └── pagination │ │ │ ├── 1.default.html │ │ │ ├── 2.large.html │ │ │ └── 3.small.html │ │ └── 3.organisms.html ├── assets.js ├── sass.js ├── templates.js └── views │ ├── content.njk │ ├── css.njk │ ├── js.njk │ ├── layout.njk │ ├── macro │ ├── element-tree.njk │ ├── navigation.njk │ └── search-tree.njk │ └── navigation.njk └── index.js /.gitattributes: -------------------------------------------------------------------------------- 1 | demo/* linguist-vendored 2 | *.njk linguist-language=Javascript -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | /demo/public/component-library 3 | /node_modules 4 | /.DS_Store 5 | /npm-debug.log 6 | /dist 7 | _tmp -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | /.gitattributes 3 | /demo 4 | /src 5 | __tests__ 6 | *.test.js 7 | .travis.yml -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | cache: 4 | directories: 5 | - node_modules 6 | notifications: 7 | email: false 8 | node_js: 9 | - '4' 10 | before_install: 11 | - npm i -g npm@^2.0.0 12 | before_script: 13 | - npm prune 14 | script: 15 | - npm run test 16 | - npm run build 17 | after_success: 18 | - npm run semantic-release 19 | branches: 20 | except: 21 | - /^v\d+\.\d+\.\d+$/ 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | An easy way to create HTML styleguide for a web project. 2 | 3 | Demo: http://sneas.github.io/component-library/index.html 4 | 5 | [![travis build](https://img.shields.io/travis/sneas/component-library.svg?style=flat-square&maxAge=2592000)](https://travis-ci.org/sneas/component-library) 6 | [![version](https://img.shields.io/npm/v/component-library.svg?style=flat-square)](http://npm.im/component-library) 7 | [![MIT License](https://img.shields.io/npm/l/component-library.svg?style=flat-square)](http://opensource.org/licenses/MIT) 8 | [![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg?style=flat-square)](https://github.com/semantic-release/semantic-release) 9 | 10 | 11 | ## Motivation 12 | 13 | Most web projects consist of components. They could be simple basic components like texts, icons, buttons, and form inputs. Or complex components like video player, sophisticated inputs (i.e., typeahead), menus, popovers, etc. Any large project reaches a point when it's hard to remember and control all the pages and their components. 14 | 15 | A component library is a special place to store and manage all the HTML components of a website in one place. 16 | 17 | Features: 18 | * easy to install 19 | * easy to manage 20 | * easy to integrate with existing project 21 | * absence of conflicts with existing JS and CSS 22 | 23 | ## Installation 24 | 25 | ```bash 26 | npm install component-library 27 | ``` 28 | 29 | ## Integration with project 30 | 31 | ### List of components 32 | 33 | Create an empty folder in your projects's file system and fill it with HTML files (components). One HTML file per one component. 34 | 35 | See [demo/src/templates](demo/src/templates) as an example. 36 | 37 | ### Integration with build process 38 | 39 | As a reference I've used Gulp but it's easy to add components library into any build system. All you need is to require component library, point it to your newly created components folder and give it links to your projects's CSS and JS files. 40 | 41 | ```javascript 42 | var gulp = require('gulp'), 43 | componentLibrary = require('component-library'); 44 | 45 | gulp.task('cl', function(cb) { 46 | componentLibrary( 47 | '/project/templates/dir', 48 | '/project/public/component-library', 49 | { 50 | baseUrl: '/component-library/', 51 | favicon: { 52 | href: '/project/favicon.ico', 53 | rel: 'shortcut icon', 54 | type: 'image/x-icon' 55 | }, 56 | js: [ 57 | //List of your project's JS files goes here 58 | '/project/js/file.js' 59 | ], 60 | css: [ 61 | //List of your project's CSS files goes here 62 | '/project/css/file.css' 63 | ] 64 | } 65 | ).then(function() { 66 | cb(); 67 | }).catch(function(er) { 68 | cb(er); 69 | }); 70 | }); 71 | 72 | gulp.task('cl:watch', ['cl'], function() { 73 | gulp.watch(['/project/templates/dir'], ['cl']); 74 | }); 75 | ``` 76 | 77 | ## FAQ 78 | ### What if my project has a custom initialization logic in layout? 79 | Create you own layout file by copying minimum HTML required: 80 | 81 | ```html 82 | 83 | 84 | 85 | 86 | {{ content }} 87 | 88 | 89 | ``` 90 | 91 | Add your custom code to it. **NB:** You can add only the required code. All the CSS links and JS scripts will be added automatically. 92 | Add the `layout` param to the configuration object. Example: 93 | ```javascript 94 | var componentLibrary = require('component-library'); 95 | 96 | componentLibrary( 97 | '/project/component-library/templates/dir', 98 | '/project/public/component-library', 99 | { 100 | layout: '/project/component-library/your-layout.html', 101 | baseUrl: '/component-library/', 102 | favicon: { 103 | href: '/project/favicon.ico', 104 | rel: 'shortcut icon', 105 | type: 'image/x-icon' 106 | }, 107 | js: [ 108 | //List of your project's JS files goes here 109 | '/project/js/file.js' 110 | ], 111 | css: [ 112 | //List of your project's CSS files goes here 113 | '/project/css/file.css' 114 | ] 115 | } 116 | ); 117 | ``` 118 | 119 | See [demo/src/layout.html](demo/src/layout.html) as an example. 120 | 121 | ## License 122 | 123 | (MIT License) 124 | 125 | Copyright (c) 2016 Dima Snisarenko snisarenkodima@gmail.com 126 | 127 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 128 | 129 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 130 | 131 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 132 | -------------------------------------------------------------------------------- /assets/favicons/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sneas/component-library/7288be445f7d09612a1801fed563b9e3e4aae861/assets/favicons/favicon-32x32.png -------------------------------------------------------------------------------- /assets/js/cl.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Navigation menu 5 | */ 6 | (function($) { 7 | var collapsible = $('.cl-navigation-collapse'); 8 | 9 | function toggle() { 10 | collapsible.slideToggle('fast', function() { 11 | collapsible.toggleClass('cl-bs-in'); 12 | }); 13 | } 14 | 15 | $('.cl-navigation-toggle').click(function() { 16 | toggle(); 17 | }); 18 | 19 | $('.cl-navigation-collapse a').click(function(e) { 20 | if (!collapsible.is(':visible')) { 21 | return; 22 | } 23 | 24 | if ($(e.target).is('.cl-bs-navbar-toggle')) { 25 | return; 26 | } 27 | 28 | if ($(this).is('.cl-bs-has-submenu.cl-bs-highlighted') || !$(this).is('cl-bs-.has-submenu')) { 29 | toggle(); 30 | } 31 | }); 32 | })(jQuery); 33 | 34 | 35 | /** 36 | * Instant search 37 | */ 38 | (function($) { 39 | var input = $('#cl-search'); 40 | var wrapper = input.parents('.cl-bs-dropdown:first'); 41 | var dropdown = wrapper.find('.cl-bs-dropdown-menu'); 42 | var likelyIn = 0; 43 | var outTimeout = false; 44 | var upStrikesOnFirstItem = 0; 45 | 46 | wrapper.focusout(function() { 47 | likelyIn = likelyIn - 1; 48 | 49 | if (outTimeout) { 50 | clearTimeout(outTimeout); 51 | } 52 | 53 | outTimeout = setTimeout(function() { 54 | outTimeout = false; 55 | if (likelyIn <= 0) { 56 | wrapper.removeClass('cl-bs-open'); 57 | likelyIn = 0; 58 | } else { 59 | showWhenNeeded(); 60 | } 61 | }, 0); 62 | }); 63 | 64 | wrapper.focusin(function() { 65 | likelyIn = likelyIn + 1; 66 | showWhenNeeded(); 67 | }); 68 | 69 | input.keyup(function(event) { 70 | // Arrow down pressed 71 | if (event.keyCode === 40) { 72 | dropdown.find('li:not(.cl-bs-hidden):first a').focus(); 73 | upStrikesOnFirstItem = 1; 74 | return; 75 | } 76 | 77 | var searchString = input.val().toLowerCase(); 78 | dropdown.find('li').each(function() { 79 | $(this).toggleClass('cl-bs-hidden', $(this).find('.cl-js-search-in') 80 | .text().toLowerCase().indexOf(searchString) === -1); 81 | }); 82 | 83 | showWhenNeeded(); 84 | }); 85 | 86 | dropdown.keyup(function(event) { 87 | // Arrow up pressed 88 | if (event.keyCode === 38) { 89 | if (dropdown.find('a:focus').parent()[0] === dropdown.find('li:visible:first')[0]) { 90 | if (++upStrikesOnFirstItem === 2) { 91 | input.focus(); 92 | upStrikesOnFirstItem = 0; 93 | } 94 | } 95 | } else { 96 | upStrikesOnFirstItem = 0; 97 | } 98 | }); 99 | 100 | dropdown.keydown(function(event) { 101 | if (event.keyCode === 13) { 102 | input.val(''); 103 | } 104 | }); 105 | 106 | function showWhenNeeded() { 107 | if (input.val().length === 0 || dropdown.find('li:not(.cl-bs-hidden)').length === 0) { 108 | wrapper.removeClass('cl-bs-open'); 109 | } else { 110 | wrapper.addClass('cl-bs-open'); 111 | } 112 | } 113 | })(jQuery); 114 | 115 | 116 | /** 117 | * Show/hide code 118 | */ 119 | (function($) { 120 | $('.cl-js-template-code-toggle').click(function() { 121 | $(this).parent().find('.cl-js-template-code-content').slideToggle('fast'); 122 | }); 123 | })(jQuery); 124 | -------------------------------------------------------------------------------- /demo/assets/project.css: -------------------------------------------------------------------------------- 1 | textarea { 2 | background-color: #d8ffff; 3 | } -------------------------------------------------------------------------------- /demo/assets/project.js: -------------------------------------------------------------------------------- 1 | //"use strict"; 2 | (function(document){ 3 | Array.prototype.forEach.call(document.getElementsByTagName('textarea'), function(element) { 4 | element.onclick = function() { 5 | alert('Element is clicked!'); 6 | } 7 | }); 8 | })(document); -------------------------------------------------------------------------------- /demo/gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'), 2 | path = require('path'), 3 | clean = require('gulp-clean'), 4 | //componentLibrary = require('component-library') 5 | componentLibrary = require('../dist/index.js'); 6 | 7 | var publicDir = path.join(__dirname, 'public/component-library'); 8 | 9 | gulp.task('clean', function() { 10 | return gulp.src(publicDir, {read: false}) 11 | .pipe(clean({force: true})); 12 | }); 13 | 14 | gulp.task('assets', ['clean'], function() { 15 | gulp.src([ 16 | __dirname + '/assets/**/*' 17 | ]) 18 | .pipe(gulp.dest(publicDir)); 19 | }); 20 | 21 | gulp.task('compile', ['assets'], function(cb) { 22 | var templatesDir = path.join(__dirname, 'src/templates'); 23 | componentLibrary(templatesDir, publicDir, { 24 | baseUrl: '/component-library/', 25 | layout: path.join(__dirname, 'src/layout.html'), 26 | js: [ 27 | 'https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js', 28 | 'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js', 29 | '/component-library/project.js' 30 | ], 31 | css: [ 32 | 'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css', 33 | 'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap-theme.min.css', 34 | 'https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css', 35 | '/component-library/project.css' 36 | ] 37 | }).then(function() { 38 | cb(); 39 | }).catch(function(err) { 40 | cb(err); 41 | }); 42 | }); 43 | 44 | gulp.task('watch', ['compile'], function() { 45 | gulp.watch(['src/**/*', 'assets/**/*', '../dist/assemblers/views/**/*', '../sass/**/*', '../assets/**/*'], ['compile']); 46 | }); -------------------------------------------------------------------------------- /demo/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /demo/src/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 | {{ content }} 7 |
8 | 9 | -------------------------------------------------------------------------------- /demo/src/templates/0.intro.html: -------------------------------------------------------------------------------- 1 |

2 | Demo library based on Bootstrap CSS framework. 3 |

-------------------------------------------------------------------------------- /demo/src/templates/1.foundation/1.Colors/1.palette.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /demo/src/templates/1.foundation/1.Colors/3.color-classes.html: -------------------------------------------------------------------------------- 1 |

Muted text

2 |

Primary text

3 |

Info text

4 |

Success text

5 |

Danger text

6 |

Warning text

-------------------------------------------------------------------------------- /demo/src/templates/1.foundation/1.Colors/4.background-utilities.html: -------------------------------------------------------------------------------- 1 |

Primary Background

2 |

Info Background

3 |

Success Background

4 |

Danger Background

5 |

Warning Background

-------------------------------------------------------------------------------- /demo/src/templates/1.foundation/2.Grid/simple-grid.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
.col-md-1
4 |
.col-md-1
5 |
.col-md-1
6 |
.col-md-1
7 |
.col-md-1
8 |
.col-md-1
9 |
.col-md-1
10 |
.col-md-1
11 |
.col-md-1
12 |
.col-md-1
13 |
.col-md-1
14 |
.col-md-1
15 |
16 | 17 |
18 |
.col-md-8
19 |
.col-md-4
20 |
21 | 22 |
23 |
.col-md-4
24 |
.col-md-4
25 |
.col-md-4
26 |
27 | 28 |
29 |
.col-md-6
30 |
.col-md-6
31 |
32 |
-------------------------------------------------------------------------------- /demo/src/templates/1.foundation/Addresses.html: -------------------------------------------------------------------------------- 1 |
2 | Twitter, Inc.
3 | 795 Folsom Ave, Suite 600
4 | San Francisco, CA 94107
5 | P: (123) 456-7890 6 |
7 |
8 | Full Name
9 | first.last@example.com 10 |
-------------------------------------------------------------------------------- /demo/src/templates/1.foundation/Alerts.html: -------------------------------------------------------------------------------- 1 |
2 | Warning Message! Lorem ipsum dolor sit amet, consectetur adipisicing elit. 3 |
4 |
5 | Error Message! Numquam quos fuga quam suscipit sapiente perferendis magnam. 6 |
7 |
8 | Success Message! Totam officiis dolorum voluptatibus maxime molestiae iste. 9 |
10 |
11 | Info Message! Consequatur facere deleniti cumque ducimus maiores nemo. 12 |
-------------------------------------------------------------------------------- /demo/src/templates/1.foundation/Badges.html: -------------------------------------------------------------------------------- 1 | 6 |
7 | 22 |
23 | -------------------------------------------------------------------------------- /demo/src/templates/1.foundation/Buttons/1.basic.html: -------------------------------------------------------------------------------- 1 |

2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |

10 |

11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |

19 |

20 | 21 | 22 | 23 | 24 | 25 |

-------------------------------------------------------------------------------- /demo/src/templates/1.foundation/Buttons/button-groups.html: -------------------------------------------------------------------------------- 1 | 8 |
9 |
10 | 17 |
18 |
19 |
20 |
21 | 28 |
29 |
30 |
31 |
32 | 39 |
40 |
-------------------------------------------------------------------------------- /demo/src/templates/1.foundation/Buttons/justified.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 |
6 | 7 |
8 |
9 | 10 |
11 |
-------------------------------------------------------------------------------- /demo/src/templates/1.foundation/Buttons/vertical.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 |
5 | 8 | 12 |
13 | 14 |
-------------------------------------------------------------------------------- /demo/src/templates/1.foundation/Buttons/with-dropdowns.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 | 6 |
7 | 8 | 12 |
13 |
14 |
15 |
16 | 17 |
18 |
19 |
20 | 21 | 27 |
28 | 29 |
30 | 31 | 37 |
38 | 39 |
40 | 41 | 47 |
48 | 49 |
50 | 51 | 57 |
58 | 59 |
60 | 61 | 67 |
68 | 69 |
70 | 71 | 77 |
78 | 79 |
80 |
81 | 82 |
83 | 84 | 88 | 94 |
95 | 96 |
97 | 98 | 100 | 106 |
107 | 108 |
109 | 110 | 112 | 118 |
119 | 120 |
121 | 122 | 124 | 130 |
131 | 132 |
133 | 134 | 136 | 142 |
143 | 144 |
145 | 146 | 148 | 154 |
155 | 156 |
157 |
158 | 159 |
160 | 162 | 165 |
166 | 167 |
168 | 170 | 173 |
174 | 175 |
176 | 179 | 182 |
183 |
184 |
-------------------------------------------------------------------------------- /demo/src/templates/1.foundation/Definition Lists/1.vertical.html: -------------------------------------------------------------------------------- 1 |
2 |
Description lists
3 |
A description list is perfect for defining terms.
4 |
Euismod
5 |
Vestibulum id ligula porta felis euismod semper eget lacinia odio sem nec elit.
6 |
Donec id elit non mi porta gravida at eget metus.
7 |
Malesuada porta
8 |
Etiam porta sem malesuada magna mollis euismod.
9 |
-------------------------------------------------------------------------------- /demo/src/templates/1.foundation/Definition Lists/2.horizontal.html: -------------------------------------------------------------------------------- 1 |
2 |
Description lists
3 |
A description list is perfect for defining terms.
4 |
Euismod
5 |
Vestibulum id ligula porta felis euismod semper eget lacinia odio sem nec elit.
6 |
Donec id elit non mi porta gravida at eget metus.
7 |
Malesuada porta
8 |
Etiam porta sem malesuada magna mollis euismod.
9 |
Felis euismod semper eget lacinia
10 |
Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet 11 | risus. 12 |
13 |
-------------------------------------------------------------------------------- /demo/src/templates/1.foundation/Dropdowns.html: -------------------------------------------------------------------------------- 1 | 16 | -------------------------------------------------------------------------------- /demo/src/templates/1.foundation/Forms/1.basic-example.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 5 |
6 |
7 | 8 | 9 |
10 |
11 | 12 | 13 |

Example block-level help text here.

14 |
15 |
16 | 19 |
20 | 21 |
-------------------------------------------------------------------------------- /demo/src/templates/1.foundation/Forms/2.inline-form.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 5 |
6 |
7 | 8 | 9 |
10 | 11 |
-------------------------------------------------------------------------------- /demo/src/templates/1.foundation/Forms/3.horizontal-form.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 | 6 |
7 |
8 |
9 | 10 |
11 | 12 |
13 |
14 |
15 |
16 |
17 | 20 |
21 |
22 |
23 |
24 |
25 | 26 |
27 |
28 |
-------------------------------------------------------------------------------- /demo/src/templates/1.foundation/Images.html: -------------------------------------------------------------------------------- 1 |

2 | 3 | 4 | 5 |

6 |

7 | -------------------------------------------------------------------------------- /demo/src/templates/1.foundation/Labels.html: -------------------------------------------------------------------------------- 1 |

Example heading New

2 |

Example heading New

3 |

Example heading New

4 |

Example heading New

5 |
Example heading New
6 |
Example heading New
7 | Default 8 | Primary 9 | Success 10 | Info 11 | Warning 12 | Danger -------------------------------------------------------------------------------- /demo/src/templates/1.foundation/Tables.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 |
#First NameTables
1MichaelAre formatted like this
2LucilleDo you like them?
3Success
4Danger
5Warning
6Active
42 |

Striped & condensed table with alternating backgrounds

43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 |
#First NameTables
1MichaelThis one is bordered and condensed
2LucilleDo you still like it?
-------------------------------------------------------------------------------- /demo/src/templates/1.foundation/Typography/1.blockquote.html: -------------------------------------------------------------------------------- 1 |
2 |

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer posuere erat a ante.

3 | 4 |
-------------------------------------------------------------------------------- /demo/src/templates/1.foundation/Typography/2.blockquote-reverse.html: -------------------------------------------------------------------------------- 1 |
2 |

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer posuere erat a ante.

3 | 4 |
-------------------------------------------------------------------------------- /demo/src/templates/1.foundation/Typography/Emphasis/bold-text.html: -------------------------------------------------------------------------------- 1 | Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Duis mollis, est non commodo luctus. -------------------------------------------------------------------------------- /demo/src/templates/1.foundation/Typography/Emphasis/italics-text.html: -------------------------------------------------------------------------------- 1 | Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Duis mollis, est non commodo luctus. -------------------------------------------------------------------------------- /demo/src/templates/1.foundation/Typography/Emphasis/small-text.html: -------------------------------------------------------------------------------- 1 | Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Duis mollis, est non commodo luctus. -------------------------------------------------------------------------------- /demo/src/templates/1.foundation/Typography/Lists/list-inline.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /demo/src/templates/1.foundation/Typography/Lists/list-ordered.html: -------------------------------------------------------------------------------- 1 |
    2 |
  1. List Item 1 3 |
  2. List Item 2
  3. 4 |
  4. List Item 3 5 | 11 |
  5. 12 |
  6. List Item 4
  7. 13 | 14 |
-------------------------------------------------------------------------------- /demo/src/templates/1.foundation/Typography/Lists/list-unordered.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /demo/src/templates/1.foundation/Typography/Lists/list-unstyled.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /demo/src/templates/1.foundation/Typography/body-copy.html: -------------------------------------------------------------------------------- 1 |

Lead paragraph: vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Duis mollis, est 2 | non commodo luctus.

3 |

Nullam quis risus eget urna mollis ornare vel eu leo. Cum sociis natoque penatibus et magnis dis 4 | parturient montes, nascetur ridiculus mus. Nullam id dolor id nibh ultricies vehicula.

5 |

6 | This line of text is meant to be treated as fine print. 7 |

8 |

The following snippet of text is rendered as bold text.

9 |

The following snippet of text is rendered as italicized text.

10 |

An abbreviation of the word attribute is attr.

-------------------------------------------------------------------------------- /demo/src/templates/1.foundation/Typography/headings.html: -------------------------------------------------------------------------------- 1 |

Heading 1

2 |

Heading 2

3 |

Heading 3

4 |

Heading 4

5 |
Heading 5
6 |
Heading 6
-------------------------------------------------------------------------------- /demo/src/templates/1.foundation/Typography/lead-copy.html: -------------------------------------------------------------------------------- 1 |

This is an example of a lead paragraph. WinShape Camps offers day and overnight summer camp experiences for boys and girls of all ages.

-------------------------------------------------------------------------------- /demo/src/templates/1.foundation/Typography/links.html: -------------------------------------------------------------------------------- 1 | Default link -------------------------------------------------------------------------------- /demo/src/templates/1.foundation/Typography/text-alignment.html: -------------------------------------------------------------------------------- 1 |

Left Alignment

2 |

Center Alignment

3 |

Right Alignment

4 |

Justified Text

-------------------------------------------------------------------------------- /demo/src/templates/1.foundation/Well.html: -------------------------------------------------------------------------------- 1 |
2 | Look, I'm in a well! 3 |
4 |
5 | Small Well 6 |
7 |
8 | Large Padding Well 9 |
10 | -------------------------------------------------------------------------------- /demo/src/templates/1.foundation/icons.html: -------------------------------------------------------------------------------- 1 |

2 | All icons are listed below and can only be used using the fa class. 3 | 4 |

5 | 6 | -------------------------------------------------------------------------------- /demo/src/templates/2.components/Media Objects/default.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | media-object 4 | 5 |
6 |

Media heading

7 | Cras sit amet nibh libero, in gravida nulla. Nulla vel metus scelerisque ante sollicitudin commodo. Cras purus 8 | odio, vestibulum in vulputate at, tempus viverra turpis. Fusce condimentum nunc ac nisi vulputate fringilla. 9 | Donec lacinia congue felis in faucibus. 10 |
11 |
12 |
13 | 14 | media-object 15 | 16 |
17 |

Media heading

18 | Cras sit amet nibh libero, in gravida nulla. Nulla vel metus scelerisque ante sollicitudin commodo. Cras purus 19 | odio, vestibulum in vulputate at, tempus viverra turpis. Fusce condimentum nunc ac nisi vulputate fringilla. 20 | Donec lacinia congue felis in faucibus. 21 |
22 | 23 | media-object 24 | 25 |
26 |

Nested media heading

27 | Cras sit amet nibh libero, in gravida nulla. Nulla vel metus scelerisque ante sollicitudin commodo. Cras 28 | purus odio, vestibulum in vulputate at, tempus viverra turpis. Fusce condimentum nunc ac nisi vulputate 29 | fringilla. Donec lacinia congue felis in faucibus. 30 |
31 |
32 |
33 |
-------------------------------------------------------------------------------- /demo/src/templates/2.components/Media Objects/list.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /demo/src/templates/2.components/Navigation/1.Navbar.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /demo/src/templates/2.components/Navigation/2.Tabs.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /demo/src/templates/2.components/Navigation/3.Justified-Tabs.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /demo/src/templates/2.components/Navigation/4.Pills.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /demo/src/templates/2.components/Navigation/5.Stacked-Pills.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /demo/src/templates/2.components/Navigation/6.Dropdown-Tabs.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /demo/src/templates/2.components/Pagination/1.default.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /demo/src/templates/2.components/Pagination/2.large.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /demo/src/templates/2.components/Pagination/3.small.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /demo/src/templates/2.components/breadcrumbs.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /demo/src/templates/2.components/list-groups.html: -------------------------------------------------------------------------------- 1 | 10 |
11 | A link 12 | 13 |

Try drying chickpeas paste blended with truffels sauce.

14 |

Per guest prepare six peaces of vinegar with pressed ground beef for dessert.

15 |
16 | 17 |

To the divided garlic add bagel, steak, salsa verde and packaged asparagus.

18 |

Per guest prepare four tablespoons of red wine with warmed ghee for dessert.

19 |
20 |
-------------------------------------------------------------------------------- /demo/src/templates/2.components/pager.html: -------------------------------------------------------------------------------- 1 | 5 | -------------------------------------------------------------------------------- /demo/src/templates/2.components/progress-bars.html: -------------------------------------------------------------------------------- 1 |

Basic

2 |
3 |
5 | 60% Complete 6 |
7 |
8 |
9 |
11 | 60% 12 |
13 |
14 |

Contextual Alternatives

15 |
16 |
18 | 40% Complete (success) 19 |
20 |
21 |
22 |
24 | 20% Complete 25 |
26 |
27 |
28 |
30 | 60% Complete (warning) 31 |
32 |
33 |
34 |
36 | 80% Complete 37 |
38 |
39 |

Striped

40 |
41 |
43 | 40% Complete (success) 44 |
45 |
46 |
47 |
49 | 20% Complete 50 |
51 |
52 |
53 |
55 | 60% Complete (warning) 56 |
57 |
58 |
59 |
61 | 80% Complete (danger) 62 |
63 |
64 |

Animated

65 |
66 |
68 | 45% Complete 69 |
70 |
71 |

Stacked

72 |
73 |
74 | 35% Complete (success) 75 |
76 |
77 | 20% Complete (warning) 78 |
79 |
80 | 10% Complete (danger) 81 |
82 |
-------------------------------------------------------------------------------- /demo/src/templates/2.components/thumbnails.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 100%x180 7 | 8 |
9 |
10 | 11 | 100%x180 14 | 15 |
16 |
17 | 18 | 100%x180 21 | 22 |
23 |
24 | 25 | 100%x180 28 | 29 |
30 |
-------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "component-library", 3 | "description": "An easy way to create HTML styleguide for your project.", 4 | "author": "Dima Snisarenko ", 5 | "license": "MIT", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/sneas/component-library.git" 9 | }, 10 | "keywords": [ 11 | "ui", 12 | "component-library", 13 | "styleguide" 14 | ], 15 | "main": "dist/index.js", 16 | "scripts": { 17 | "commit": "git-cz", 18 | "test": "mocha src/**/*.test.js --compilers js:babel-register", 19 | "posttest": "rimraf **/_tmp", 20 | "prebuild": "rimraf dist", 21 | "build": "babel --out-dir dist --ignore __tests__,*.test.js src --copy-files", 22 | "build:watch": "watch 'npm run build' src sass", 23 | "precompile-demo": "npm run build", 24 | "compile-demo": "gulp --gulpfile demo/gulpfile.js compile", 25 | "predemo": "npm run compile-demo", 26 | "demo": "ws -d ./demo/public -c", 27 | "semantic-release": "semantic-release pre && npm publish && semantic-release post", 28 | "prepublish-demo": "npm run compile-demo", 29 | "publish-demo": "gh-pages -d demo/public/component-library" 30 | }, 31 | "dependencies": { 32 | "bootstrap-sass-namespace": "3.3.7-alpha.6", 33 | "cheerio": "^0.22.0", 34 | "copy-dir": "0.3.0", 35 | "directory-tree": "^1.0.0", 36 | "font-awesome": "^4.6.3", 37 | "highlight.js": "9.9.0", 38 | "jquery": "^3.2.1", 39 | "lodash": "^4.13.1", 40 | "node-modules-resolve": "^1.3.0", 41 | "npm-sass": "^1.3.0", 42 | "nunjucks": "3.0.0", 43 | "smartmenus-namespace": "1.0.1-alpha.5", 44 | "writefile": "^0.2.8" 45 | }, 46 | "devDependencies": { 47 | "babel-cli": "6.18.0", 48 | "babel-core": "6.18.2", 49 | "babel-preset-es2015": "6.18.0", 50 | "babel-preset-stage-2": "6.18.0", 51 | "babel-register": "6.18.0", 52 | "chai": "3.5.0", 53 | "chai-fs": "1.0.0", 54 | "cheerio": "0.22.0", 55 | "commitizen": "2.8.6", 56 | "cz-conventional-changelog": "1.2.0", 57 | "gh-pages": "0.12.0", 58 | "ghooks": "1.3.2", 59 | "gulp": "^3.9.1", 60 | "gulp-clean": "^0.3.2", 61 | "local-web-server": "^1.2.6", 62 | "mocha": "3.1.2", 63 | "rimraf": "2.5.4", 64 | "semantic-release": "^6.3.2", 65 | "watch": "1.0.1" 66 | }, 67 | "config": { 68 | "ghooks": { 69 | "pre-commit": "npm run test" 70 | }, 71 | "commitizen": { 72 | "path": "node_modules/cz-conventional-changelog" 73 | } 74 | }, 75 | "babel": { 76 | "presets": [ 77 | "es2015", 78 | "stage-2" 79 | ] 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /sass/_components.scss: -------------------------------------------------------------------------------- 1 | @import "components/palette"; 2 | @import "components/icon-list"; -------------------------------------------------------------------------------- /sass/_init.scss: -------------------------------------------------------------------------------- 1 | // Initialize Bootstrap 2 | @import "bootstrap/variables"; 3 | @import "bootstrap-sass-namespace/assets/stylesheets/_bootstrap.scss"; 4 | @import "bootstrap/theme"; 5 | 6 | // Initialize highlight.js 7 | .cl { 8 | @import "highlight.js/styles/github"; 9 | } 10 | 11 | // Initialize Smartmenus 12 | @import "smartmenus-namespace/dist/addons/bootstrap/jquery.smartmenus.bootstrap"; 13 | 14 | // Initialize Font Awesome 15 | $fa-font-path: "../fonts" !default; 16 | $fa-css-prefix: cl-fa !default; 17 | @import "font-awesome/scss/font-awesome"; -------------------------------------------------------------------------------- /sass/_tree.scss: -------------------------------------------------------------------------------- 1 | .cl-node { 2 | $anchor-offset: $navbar-height + 50px; 3 | 4 | padding-top:$anchor-offset; 5 | margin-top:-$anchor-offset; 6 | } 7 | 8 | .cl-node-level-1 { 9 | .cl-node-subtree { 10 | padding: 10px; 11 | border-top: 1px dotted #eaeaea; 12 | border-left: 2px solid transparent; 13 | 14 | &:hover { 15 | border-left: 2px solid #eaeaea; 16 | } 17 | } 18 | } 19 | 20 | .cl-node-temaplate-code { 21 | margin-top: 10px; 22 | 23 | .cl-node-template-code-content { 24 | margin-top: 10px; 25 | display: none; 26 | 27 | &[cl-visible] { 28 | display: block; 29 | } 30 | } 31 | } 32 | 33 | .cl-node-header { 34 | .cl-node-header-link { 35 | margin-left: 0.5em; 36 | color: $headings-color !important; 37 | font-weight: normal !important; 38 | visibility: hidden; 39 | } 40 | 41 | &:hover { 42 | .cl-node-header-link { 43 | visibility: visible; 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /sass/bootstrap/_theme.scss: -------------------------------------------------------------------------------- 1 | .#{$class-prefix}-navbar-inverse { 2 | background-image: none; 3 | } 4 | 5 | .#{$class-prefix}-dropdown-menu > .#{$class-prefix}-html-li > .#{$class-prefix}-html-a:hover, 6 | .#{$class-prefix}-dropdown-menu > .#{$class-prefix}-html-li > .#{$class-prefix}-html-a:focus { 7 | background-image: none; 8 | outline: none; 9 | } 10 | 11 | .#{$class-prefix}-navbar-toggle { 12 | @include navbar-vertical-align(30px); 13 | margin-top: 0; 14 | margin-bottom: 0; 15 | } 16 | 17 | .#{$class-prefix}-navbar-nav { 18 | @media (min-width: $grid-float-breakpoint) { 19 | margin-left: -30px; 20 | } 21 | } 22 | 23 | .#{$class-prefix}-navbar-form { 24 | padding-right: 0px; 25 | } 26 | 27 | .#{$class-prefix}-nav .#{$class-prefix}-open > .#{$class-prefix}-html-a, 28 | .#{$class-prefix}-nav .#{$class-prefix}-open > .#{$class-prefix}-html-a:hover, 29 | .#{$class-prefix}-nav .#{$class-prefix}-open > .#{$class-prefix}-html-a:focus { 30 | @media (max-width: $grid-float-breakpoint) { 31 | background-color: transparent; 32 | border-color: transparent; 33 | } 34 | } 35 | 36 | .cl-navbar-placeholder { 37 | min-height: $navbar-height; 38 | } 39 | 40 | .cl-search-menu { 41 | left: auto; 42 | right: 0; 43 | } -------------------------------------------------------------------------------- /sass/bootstrap/_variables.scss: -------------------------------------------------------------------------------- 1 | $border-radius-base: 0px; 2 | $navbar-inverse-bg: #333333; 3 | $padding-base-vertical: 0px; 4 | $navbar-padding-vertical: 5px; 5 | $navbar-height: 30px; 6 | $class-prefix: cl-bs; 7 | @import "bootstrap-sass-namespace/assets/stylesheets/bootstrap/_variables.scss"; -------------------------------------------------------------------------------- /sass/cl.scss: -------------------------------------------------------------------------------- 1 | @import "init"; 2 | @import "tree"; 3 | @import "components"; -------------------------------------------------------------------------------- /sass/components/_icon-list.scss: -------------------------------------------------------------------------------- 1 | .cl-icon-list { 2 | list-style: none; 3 | padding: 0; 4 | @include clearfix; 5 | 6 | 7 | >li { 8 | float: left; 9 | width: 25%; 10 | height: 115px; 11 | padding: 10px; 12 | font-size: 10px; 13 | line-height: 1.4; 14 | text-align: center; 15 | background-color: #f9f9f9; 16 | border: 1px solid #fff; 17 | 18 | @media (min-width: $screen-sm-min) { 19 | width: 12.5%; 20 | font-size: 12px; 21 | } 22 | 23 | >span:first-child { 24 | font-size: 24px; 25 | margin-bottom: 10px; 26 | } 27 | 28 | >span:last-child { 29 | display: block; 30 | word-wrap: break-word; 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /sass/components/_palette.scss: -------------------------------------------------------------------------------- 1 | $color-border-radius: 5px !default; 2 | 3 | .cl-palette { 4 | @extend .cl; 5 | 6 | $media-screen-padding: 5px; 7 | 8 | padding: 0; 9 | list-style: none; 10 | text-align: center; 11 | 12 | @media (min-width: $screen-md-min) { 13 | margin-left: -$media-screen-padding; 14 | margin-right: -$media-screen-padding; 15 | li { 16 | display: table-cell; 17 | vertical-align: top; 18 | width: 1%; 19 | padding: 0 $media-screen-padding; 20 | } 21 | } 22 | 23 | li { 24 | color: #fff; 25 | } 26 | 27 | h3 { 28 | color: #333; 29 | font-size: 14px; 30 | font-weight: 600; 31 | margin: 20px 0 10px 0; 32 | } 33 | 34 | .color { 35 | height: 120px; 36 | padding-top: 1.5em; 37 | 38 | &:first-of-type { 39 | border-top-left-radius: $color-border-radius; 40 | border-top-right-radius: $color-border-radius; 41 | } 42 | 43 | &:last-of-type { 44 | border-bottom-right-radius: $color-border-radius; 45 | border-bottom-left-radius: $color-border-radius; 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /src/assemblers/__tests__/assets.test.js: -------------------------------------------------------------------------------- 1 | import chai, {expect} from 'chai'; 2 | import chaiFs from 'chai-fs'; 3 | import assembleAssets from '../assets.js'; 4 | import path from 'path'; 5 | 6 | chai.use(chaiFs); 7 | 8 | describe('assets assembler', function() { 9 | it('should assemble assets', function(done) { 10 | const outputDir = path.join(__dirname, 'assets/_tmp/asserts'); 11 | assembleAssets(path.join(__dirname, 'assets/input'), 12 | path.join(__dirname, 'assets/_tmp/asserts')) 13 | .then(function() { 14 | expect(outputDir).to.be.directory('Assets output directory has been created'); 15 | expect(path.join(outputDir, 'test-asset.txt')).to.be.file('Root file has been created'); 16 | expect(path.join(outputDir, 'folder/another-asset.txt')).to.be.file('Dir file has been created'); 17 | 18 | done(); 19 | }); 20 | }); 21 | }); -------------------------------------------------------------------------------- /src/assemblers/__tests__/assets/input/folder/another-asset.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sneas/component-library/7288be445f7d09612a1801fed563b9e3e4aae861/src/assemblers/__tests__/assets/input/folder/another-asset.txt -------------------------------------------------------------------------------- /src/assemblers/__tests__/assets/input/test-asset.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sneas/component-library/7288be445f7d09612a1801fed563b9e3e4aae861/src/assemblers/__tests__/assets/input/test-asset.txt -------------------------------------------------------------------------------- /src/assemblers/__tests__/sass.test.js: -------------------------------------------------------------------------------- 1 | import chai, {expect} from 'chai'; 2 | import chaiFs from 'chai-fs'; 3 | import assembleSass from '../sass.js'; 4 | import path from 'path'; 5 | 6 | chai.use(chaiFs); 7 | 8 | describe('sass assembler', function() { 9 | it('should successfully assemble sass', function(done) { 10 | const output = path.resolve(__dirname, 'sass/_tmp/good.scss'); 11 | assembleSass(path.resolve(__dirname, 'sass/input/good.scss'), output) 12 | .then(function() { 13 | expect(output).to.be.file('Valid SCSS file has been compile'); 14 | done(); 15 | }); 16 | }); 17 | 18 | it('should not assemble sass', function(done) { 19 | const output = path.resolve(__dirname, 'sass/_tmp/bad.scss'); 20 | assembleSass(path.resolve(__dirname, 'sass/input/bad.scss'), output) 21 | .catch(function() { 22 | expect(output).to.not.be.a.path('Erroneous SCSS file has not been compiled. Promise rejected'); 23 | done(); 24 | }); 25 | }); 26 | }); -------------------------------------------------------------------------------- /src/assemblers/__tests__/sass/input/bad.scss: -------------------------------------------------------------------------------- 1 | // With this bad SCSS file we're testing failed CSS generation 2 | 3 | @import 'unexisting'; -------------------------------------------------------------------------------- /src/assemblers/__tests__/sass/input/good.scss: -------------------------------------------------------------------------------- 1 | // With this good SCSS file we're testing successful CSS generation 2 | 3 | html { 4 | a { 5 | color: Red; 6 | } 7 | } -------------------------------------------------------------------------------- /src/assemblers/__tests__/templates.test.js: -------------------------------------------------------------------------------- 1 | import chai, {expect} from 'chai'; 2 | import chaiFs from 'chai-fs'; 3 | import assembleTemplates from '../templates.js'; 4 | import path from 'path'; 5 | import cheerio from 'cheerio'; 6 | import fs from 'fs'; 7 | 8 | chai.use(chaiFs); 9 | 10 | describe('templates assembler', function() { 11 | it('should successfully assemble templates', function(done) { 12 | const inputDir = path.join(__dirname, 'templates/input'); 13 | const outputDir = path.join(__dirname, 'templates/_tmp/output'); 14 | assembleTemplates(inputDir, outputDir).then(function() { 15 | const overviewFile = path.join(outputDir, 'index.html'); 16 | expect(outputDir).to.be.directory('Output templates dir has been created'); 17 | expect(overviewFile).to.be.file('Overview file has been generated'); 18 | 19 | const $ = cheerio.load(fs.readFileSync(overviewFile, 'utf8'), { 20 | normalizeWhitespace: true 21 | }); 22 | expect($('.cl-node-header.cl-bs-html-h1').text().trim()).to.be.equal('Overview'); 23 | done(); 24 | }); 25 | }); 26 | 27 | it('should set custom overview lable', function(done) { 28 | const inputDir = path.join(__dirname, 'templates/input'); 29 | const outputDir = path.join(__dirname, 'templates/_tmp/output'); 30 | assembleTemplates(inputDir, outputDir, { 31 | overview: 'Outline' 32 | }).then(function() { 33 | const overviewFile = path.join(outputDir, 'index.html'); 34 | const $ = cheerio.load(fs.readFileSync(overviewFile, 'utf8'), { 35 | normalizeWhitespace: true 36 | }); 37 | expect($('.cl-node-header.cl-bs-html-h1').text().trim()).to.be.equal('Outline'); 38 | expect($('#cl-search').attr('placeholder')).to.be.equal('Search'); 39 | done(); 40 | }); 41 | }); 42 | 43 | it('should set custom search placeholder', function(done) { 44 | const inputDir = path.join(__dirname, 'templates/input'); 45 | const outputDir = path.join(__dirname, 'templates/_tmp/output'); 46 | assembleTemplates(inputDir, outputDir, { 47 | search: 'Find' 48 | }).then(function() { 49 | const overviewFile = path.join(outputDir, 'index.html'); 50 | const $ = cheerio.load(fs.readFileSync(overviewFile, 'utf8'), { 51 | normalizeWhitespace: true 52 | }); 53 | expect($('#cl-search').attr('placeholder')).to.be.equal('Find'); 54 | done(); 55 | }); 56 | }); 57 | 58 | it('should create search menu', function(done) { 59 | const inputDir = path.join(__dirname, 'templates/input'); 60 | const outputDir = path.join(__dirname, 'templates/_tmp/output'); 61 | assembleTemplates(inputDir, outputDir).then(function() { 62 | const overviewFile = path.join(outputDir, 'index.html'); 63 | const $ = cheerio.load(fs.readFileSync(overviewFile, 'utf8'), { 64 | normalizeWhitespace: true 65 | }); 66 | expect($('.cl-search-menu').find('li:nth-child(1) .cl-js-not-search-in').text().trim()).to.be.equal(''); 67 | expect($('.cl-search-menu').find('li:nth-child(1) .cl-js-search-in').text().trim()).to.be.equal('Overview'); 68 | 69 | expect($('.cl-search-menu').find('li:nth-child(2) .cl-js-not-search-in').text().trim()).to.be.equal(''); 70 | expect($('.cl-search-menu').find('li:nth-child(2) .cl-js-search-in').text().trim()).to.be.equal('Atoms'); 71 | 72 | expect($('.cl-search-menu').find('li:nth-child(3) .cl-js-not-search-in').text().trim()).to.be.equal('Atoms →'); 73 | expect($('.cl-search-menu').find('li:nth-child(3) .cl-js-search-in').text().trim()).to.be.equal('Colors'); 74 | 75 | expect($('.cl-search-menu').find('li:nth-child(4) .cl-js-not-search-in').text().trim()).to.be.equal('Atoms → Colors →'); 76 | expect($('.cl-search-menu').find('li:nth-child(4) .cl-js-search-in').text().trim()).to.be.equal('Palette'); 77 | 78 | expect($('.cl-search-menu').find('li:nth-child(5) .cl-js-not-search-in').text().trim()).to.be.equal('Atoms → Colors →'); 79 | expect($('.cl-search-menu').find('li:nth-child(5) .cl-js-search-in').text().trim()).to.be.equal('Color classes'); 80 | 81 | expect($('.cl-search-menu').find('li:nth-child(6) .cl-js-not-search-in').text().trim()).to.be.equal('Atoms → Colors →'); 82 | expect($('.cl-search-menu').find('li:nth-child(6) .cl-js-search-in').text().trim()).to.be.equal('Background utilities'); 83 | 84 | expect($('.cl-search-menu').find('li:nth-child(7) .cl-js-not-search-in').text().trim()).to.be.equal('Atoms →'); 85 | expect($('.cl-search-menu').find('li:nth-child(7) .cl-js-search-in').text().trim()).to.be.equal('Alerts'); 86 | 87 | expect($('.cl-search-menu').find('li:nth-child(8) .cl-js-not-search-in').text().trim()).to.be.equal(''); 88 | expect($('.cl-search-menu').find('li:nth-child(8) .cl-js-search-in').text().trim()).to.be.equal('Molecules'); 89 | 90 | expect($('.cl-search-menu').find('li:nth-child(9) .cl-js-not-search-in').text().trim()).to.be.equal('Molecules →'); 91 | expect($('.cl-search-menu').find('li:nth-child(9) .cl-js-search-in').text().trim()).to.be.equal('Breadcrumbs'); 92 | 93 | done(); 94 | }); 95 | }); 96 | }); -------------------------------------------------------------------------------- /src/assemblers/__tests__/templates/input/1.atoms/1.Colors/1.palette.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assemblers/__tests__/templates/input/1.atoms/1.Colors/3.color-classes.html: -------------------------------------------------------------------------------- 1 |

Muted text

2 |

Primary text

3 |

Info text

4 |

Success text

5 |

Danger text

6 |

Warning text

-------------------------------------------------------------------------------- /src/assemblers/__tests__/templates/input/1.atoms/1.Colors/4.background-utilities.html: -------------------------------------------------------------------------------- 1 |

Primary Background

2 |

Info Background

3 |

Success Background

4 |

Danger Background

5 |

Warning Background

-------------------------------------------------------------------------------- /src/assemblers/__tests__/templates/input/1.atoms/alerts.html: -------------------------------------------------------------------------------- 1 |
2 | Warning Message! Lorem ipsum dolor sit amet, consectetur adipisicing elit. 3 |
4 |
5 | Error Message! Numquam quos fuga quam suscipit sapiente perferendis magnam. 6 |
7 |
8 | Success Message! Totam officiis dolorum voluptatibus maxime molestiae iste. 9 |
10 |
11 | Info Message! Consequatur facere deleniti cumque ducimus maiores nemo. 12 |
-------------------------------------------------------------------------------- /src/assemblers/__tests__/templates/input/2.molecules/breadcrumbs.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assemblers/__tests__/templates/input/2.molecules/pagination/1.default.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assemblers/__tests__/templates/input/2.molecules/pagination/2.large.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assemblers/__tests__/templates/input/2.molecules/pagination/3.small.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assemblers/__tests__/templates/input/3.organisms.html: -------------------------------------------------------------------------------- 1 |
2 | 7 | 8 |

Data

9 | 10 |

11 | Lorem ipsum
dolor sit amet. 12 |

13 |
-------------------------------------------------------------------------------- /src/assemblers/assets.js: -------------------------------------------------------------------------------- 1 | import copyDir from 'copy-dir'; 2 | 3 | export default function(inputDir, outputDir) { 4 | return new Promise(function(resolve) { 5 | copyDir(inputDir, outputDir, function(err) { 6 | if (err) { 7 | throw err; 8 | } 9 | 10 | resolve(); 11 | }); 12 | }); 13 | } -------------------------------------------------------------------------------- /src/assemblers/sass.js: -------------------------------------------------------------------------------- 1 | import sass from 'npm-sass'; 2 | import writefile from 'writefile'; 3 | 4 | export default function(input, output) { 5 | return new Promise(function(resolve, reject) { 6 | sass(input, function (err, result) { 7 | if (err) { 8 | reject(err); 9 | } else { 10 | writefile(output, result.css, function() { 11 | resolve(); 12 | }); 13 | } 14 | }) 15 | }); 16 | } -------------------------------------------------------------------------------- /src/assemblers/templates.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import fs from 'fs'; 3 | import dirTree from 'directory-tree'; 4 | import path from 'path'; 5 | import writefile from 'writefile'; 6 | import nunjucks from 'nunjucks'; 7 | import hljs from 'highlight.js'; 8 | import cheerio from 'cheerio'; 9 | 10 | let nunjucksEnv; 11 | 12 | function refineTree(item, rootDir) { 13 | //Remove firsts numbers and extensions 14 | var prettyName = item.name.replace(/^\d+\./, '').split('.').shift().replace('-', ' '); 15 | item.name = _.capitalize(prettyName); 16 | item.relativePath = path.relative(rootDir, item.path); 17 | 18 | if (item.children) { 19 | item.relativePath += (item.relativePath ? '/' : '') + 'index.html'; 20 | } 21 | 22 | _.each(item.children, function(child) { 23 | refineTree(child, rootDir) 24 | }); 25 | } 26 | 27 | function compileTree(item, outputDir, tree, options = {}) { 28 | var outputPath = path.resolve(outputDir, item.relativePath); 29 | 30 | const renderers = []; 31 | 32 | if (item.children) { 33 | _.each(item.children, function(child) { 34 | renderers.push(compileTree(child, outputDir, tree, options)); 35 | }); 36 | } 37 | 38 | renderers.push( 39 | new Promise(function(resolve, reject) { 40 | const params = _.extend({}, options, { 41 | tree: tree, 42 | current: item 43 | }); 44 | 45 | const navigationHtml = nunjucksEnv.render('navigation.njk', params); 46 | const contentHtml = nunjucksEnv.render('content.njk', params); 47 | nunjucksEnv.opts.autoescape = false; 48 | const layoutHtml = nunjucksEnv.render(options.layout, {content: contentHtml}); 49 | nunjucksEnv.opts.autoescape = true; 50 | 51 | const $ = cheerio.load(layoutHtml, { 52 | decodeEntities: false 53 | }); 54 | const head = $('head'); 55 | const body = $('body'); 56 | 57 | head.prepend(nunjucksEnv.render('css.njk', params)); 58 | 59 | if (head.find('title').length === 0) { 60 | head.prepend($('').text(options.title)); 61 | } 62 | 63 | _.forEach(options.css, function(cssLink) { 64 | head.append($('').attr('href', cssLink)); 65 | }); 66 | 67 | if (head.find('meta[charset]').length === 0) { 68 | head.prepend(''); 69 | } 70 | 71 | if (head.find('link[rel=icon]').length === 0) { 72 | head.append($('').attr('href', options.favicon.href) 73 | .attr('rel', options.favicon.rel) 74 | .attr('type', options.favicon.type)); 75 | } 76 | 77 | body.prepend(navigationHtml); 78 | body.append(nunjucks.render('js.njk', params)); 79 | 80 | _.forEach(options.js, function(jsLink) { 81 | body.append($('').attr('src', jsLink)); 82 | }); 83 | 84 | writefile(outputPath, $.html(), function() { 85 | resolve(); 86 | }); 87 | }) 88 | ); 89 | 90 | return Promise.all(renderers); 91 | } 92 | 93 | export default function(inputDir, outputDir, options = {}) { 94 | options = _.defaults({}, options, { 95 | baseUrl: '/', 96 | title: 'Component Library', 97 | overview: 'Overview', 98 | search: 'Search', 99 | js: [], 100 | css: [], 101 | layout: path.join(__dirname, 'views/layout.njk'), 102 | favicon: { 103 | href: options.baseUrl + 'assets_/assets/favicons/favicon-32x32.png', 104 | rel: 'icon', 105 | type: 'image/component-library/favicons/png' 106 | } 107 | }); 108 | 109 | nunjucksEnv = (new nunjucks.configure([path.join(__dirname, 'views'), ''])) 110 | .addFilter('template', path => fs.readFileSync(path).toString()) 111 | .addFilter('highlight', code => hljs.highlight('htmlbars', code, true, false).value); 112 | 113 | const patternsTree = dirTree(inputDir); 114 | patternsTree.name = options.overview; 115 | refineTree(patternsTree, inputDir); 116 | 117 | return compileTree(patternsTree, outputDir, patternsTree, options); 118 | } -------------------------------------------------------------------------------- /src/assemblers/views/content.njk: -------------------------------------------------------------------------------- 1 | {% from 'macro/element-tree.njk' import elementTree %} 2 | {{ elementTree(current, 1, baseUrl) }} -------------------------------------------------------------------------------- /src/assemblers/views/css.njk: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assemblers/views/js.njk: -------------------------------------------------------------------------------- 1 | 14 | 15 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/assemblers/views/layout.njk: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{ content }} 6 | 7 | -------------------------------------------------------------------------------- /src/assemblers/views/macro/element-tree.njk: -------------------------------------------------------------------------------- 1 | {% macro elementTree(element, depth, baseUrl) %} 2 |
3 |
4 |
5 |
6 | {{ element.name }} 7 | 8 | 9 | 10 |
11 |
12 |
13 | {% if element.children %} 14 |
15 | {% for child in element.children %} 16 | {{ elementTree(child, depth + 1, baseUrl) }} 17 | {% endfor %} 18 |
19 | {% else %} 20 |
21 | {{ element.path | template | safe }} 22 |
23 |
24 |
25 |
26 |
{{ element.path | template | highlight | safe }}
27 | 30 |
31 |
32 |
33 | {% endif %} 34 |
35 | {% endmacro %} -------------------------------------------------------------------------------- /src/assemblers/views/macro/navigation.njk: -------------------------------------------------------------------------------- 1 | {% macro navigation(tree, baseUrl, current) %} 2 |
  • 3 | 4 | {{ tree.name }} 5 | 6 | {% if tree.children %} 7 | 8 | {% endif %} 9 | 10 | {% if tree.children %} 11 | 16 | {% endif %} 17 |
  • 18 | {% endmacro %} -------------------------------------------------------------------------------- /src/assemblers/views/macro/search-tree.njk: -------------------------------------------------------------------------------- 1 | {% macro searchTree(tree, baseUrl, parent, level) %} 2 |
  • 3 | 4 | {{ parent }}{{ tree.name }} 5 | 6 |
  • 7 | 8 | {% if tree.children %} 9 | {% if level > 0 %} 10 | {% set parent = parent ~ tree.name ~ ' → ' %} 11 | {% endif %} 12 | {% for child in tree.children %} 13 | {{ searchTree(child, baseUrl, parent, level + 1) }} 14 | {% endfor %} 15 | {% endif %} 16 | {% endmacro %} -------------------------------------------------------------------------------- /src/assemblers/views/navigation.njk: -------------------------------------------------------------------------------- 1 | {% from 'macro/navigation.njk' import navigation %} 2 | {% from 'macro/search-tree.njk' import searchTree %} 3 |
    4 |
    5 | 33 | 34 |
    35 |
    36 |
    -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import assembleTemplates from './assemblers/templates.js'; 2 | import assembleSass from './assemblers/sass.js'; 3 | import assembleAssets from './assemblers/assets.js'; 4 | import path from 'path'; 5 | import nmResolve from 'node-modules-resolve'; 6 | 7 | module.exports = function(templatesDir, outputDir, options = {}) { 8 | return Promise.all([ 9 | assembleTemplates(templatesDir, outputDir, options), 10 | assembleSass(path.resolve(__dirname, '../sass/cl.scss'), path.join(outputDir, 'assets_/css/cl.css')), 11 | assembleAssets(path.resolve(__dirname, '../assets'), path.join(outputDir, 'assets_/assets')), 12 | assembleAssets(path.resolve(nmResolve('jquery'), 'dist'), path.join(outputDir, 'assets_/jquery')), 13 | assembleAssets(path.resolve(nmResolve('bootstrap-sass-namespace'), 'assets/javascripts/bootstrap'), path.join(outputDir, 'assets_/bootstrap-namespace')), 14 | assembleAssets(path.resolve(nmResolve('smartmenus-namespace'), 'dist'), path.join(outputDir, 'assets_/smartmenus-namespace')), 15 | assembleAssets(path.resolve(nmResolve('font-awesome'), 'fonts'), path.join(outputDir, 'assets_/fonts')) 16 | ]); 17 | }; 18 | --------------------------------------------------------------------------------