├── .editorconfig ├── .eslintrc ├── .gitignore ├── .travis.yml ├── .verb.md ├── README.md ├── appveyor.yml ├── docs └── author.md ├── package.json └── recipes ├── browser-sync ├── README.md ├── content │ └── page-1.md ├── index.js ├── less │ ├── default.less │ ├── typography.less │ └── variables.less ├── run.js └── templates │ └── layouts │ └── default.hbs ├── collection-basic ├── README.md ├── content │ ├── articles │ │ ├── article-1.md │ │ └── article-2.md │ └── pages │ │ ├── page-1.md │ │ └── page-2.md ├── helpers │ └── ctx.js ├── index.js ├── index.spec.js └── templates │ └── layouts │ └── default.hbs ├── default-layout ├── README.md ├── content │ ├── explicit.md │ └── implicit.md ├── index.js ├── index.spec.js └── templates │ └── layouts │ ├── default.hbs │ └── the-special-one.hbs ├── drafts ├── README.md ├── content │ ├── default.md │ ├── draft-false.md │ └── draft-true.md ├── index.js ├── index.spec.js └── plugins │ └── drafts.js ├── gulp-sitemap ├── README.md ├── assemblefile.js ├── assemblefile.spec.js ├── package.json └── src │ ├── layouts │ └── default.hbs │ └── pages │ ├── about.hbs │ ├── contact.hbs │ └── index.hbs ├── less ├── README.md ├── index.js ├── index.spec.js └── less │ ├── default.less │ ├── typography.less │ └── variables.less ├── lib ├── test-utils.js └── utils.js ├── loading-handlebar-helpers ├── README.md ├── content │ ├── if_eq.md │ ├── if_eq_false.md │ └── test.md ├── helpers │ ├── if_q.js │ └── test.js ├── index.js ├── index.spec.js └── run.js ├── middleware-page-toc ├── README.md ├── content │ └── article-1.md ├── index.js ├── index.spec.js ├── run.js └── templates │ └── layouts │ └── default.hbs ├── middleware ├── README.md ├── content │ └── page-1.md ├── index.js ├── index.spec.js └── run.js ├── permalinks-copy-images ├── README.md ├── content │ ├── articles │ │ ├── article-1 │ │ │ ├── README.md │ │ │ └── images │ │ │ │ ├── article-1.png │ │ │ │ └── dot.png │ │ └── article-2 │ │ │ ├── README.md │ │ │ └── images │ │ │ ├── article-2.png │ │ │ └── dot.png │ └── posts │ │ ├── 2016-01-01-post-1 │ │ ├── README.md │ │ └── images │ │ │ ├── dot.png │ │ │ └── post-1.png │ │ └── 2016-01-02-post-2 │ │ ├── README.md │ │ └── images │ │ ├── dot.png │ │ └── post-2.png ├── index.js ├── index.spec.js ├── run.js └── templates │ └── layouts │ └── index.hbs ├── permalinks-folder-per-file-filebase ├── README.md ├── assemblefile.js ├── content │ └── articles │ │ ├── bar.md │ │ ├── baz.md │ │ └── foo.md ├── index.spec.js ├── run.js └── src │ └── plugins │ └── index.js ├── permalinks-folder-per-file ├── README.md ├── content │ ├── folder-1 │ │ ├── a.md │ │ └── folder-1-1 │ │ │ ├── c.md │ │ │ └── d.md │ ├── folder-2 │ │ └── b.md │ ├── y.md │ └── z.md ├── index.js ├── index.spec.js └── run.js ├── permalinks ├── README.md ├── content │ ├── articles │ │ ├── article-1 │ │ │ └── README.md │ │ └── article-2 │ │ │ └── README.md │ └── posts │ │ └── post-1 │ │ └── README.md ├── index.js ├── index.spec.js ├── run.js └── templates │ └── layouts │ └── body.hbs ├── visual-studio-integration ├── assemblefile.js ├── bower.json ├── package.json ├── readme.md └── src │ ├── assets │ ├── css │ │ ├── carousel.css │ │ ├── ie10-viewport-bug-workaround.css │ │ └── styles.less │ ├── images │ │ └── icon.png │ └── js │ │ └── ie10-viewport-bug-workaround.js │ ├── data │ └── site.json │ ├── layouts │ └── default.hbs │ └── pages │ ├── about.hbs │ ├── contact.hbs │ └── index.hbs └── vscode-integration ├── .vscode └── tasks.json ├── README.md ├── assemblefile.js └── package.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | end_of_line = lf 9 | insert_final_newline = true 10 | 11 | # 4 tab indentation 12 | [*.*] 13 | indent_style = tab 14 | indent_size = 4 15 | 16 | # 2 space indentation for package.json since this is npm default 17 | [package.json] 18 | indent_style = space 19 | indent_size = 2 20 | 21 | # 2 space indentation for all .yml files 22 | [*.yml] 23 | indent_style = space 24 | indent_size = 2 -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "env": { 4 | "es6": false, 5 | "node": true, 6 | "mocha": true 7 | }, 8 | "ecmaFeatures": { 9 | "modules": true 10 | }, 11 | "globals": { 12 | "chai": false, 13 | "sinon": false, 14 | "expect": false 15 | }, 16 | "extends": "eslint:recommended", 17 | "rules": { 18 | "no-console": 0, 19 | "no-alert": 2, 20 | "no-array-constructor": 2, 21 | "no-caller": 2, 22 | "no-catch-shadow": 2, 23 | "no-eval": 2, 24 | "no-extend-native": 2, 25 | "no-extra-bind": 2, 26 | "no-implied-eval": 2, 27 | "no-iterator": 2, 28 | "no-label-var": 2, 29 | "no-labels": 2, 30 | "no-lone-blocks": 2, 31 | "no-loop-func": 2, 32 | "no-multi-spaces": 2, 33 | "no-multi-str": 2, 34 | "no-native-reassign": 2, 35 | "no-new": 2, 36 | "no-new-func": 2, 37 | "no-new-object": 2, 38 | "no-new-wrappers": 2, 39 | "no-octal-escape": 2, 40 | "no-process-exit": 2, 41 | "no-proto": 2, 42 | "no-return-assign": 2, 43 | "no-script-url": 2, 44 | "no-sequences": 2, 45 | "no-shadow": 2, 46 | "no-shadow-restricted-names": 2, 47 | "no-spaced-func": 2, 48 | "no-trailing-spaces": 2, 49 | "no-undef": 2, 50 | "no-undef-init": 2, 51 | "no-underscore-dangle": 2, 52 | "no-unused-expressions": 2, 53 | "no-use-before-define": 2, 54 | "no-with": 2, 55 | "camelcase": 2, 56 | "comma-spacing": 2, 57 | "consistent-return": 2, 58 | "curly": [2, "all"], 59 | "dot-notation": [2, { "allowKeywords": true }], 60 | "eol-last": 2, 61 | "no-extra-parens": [2, "functions"], 62 | "eqeqeq": 2, 63 | "key-spacing": [2, { "beforeColon": false, "afterColon": true }], 64 | "new-cap": [2, { 65 | "capIsNewExceptions": ["Router", "Promise"] 66 | }], 67 | "new-parens": 2, 68 | "quotes": [2, "single"], 69 | "semi": 2, 70 | "semi-spacing": [2, {"before": false, "after": true}], 71 | "space-infix-ops": 2, 72 | "space-in-parens": [2, "always"], 73 | "keyword-spacing": 2, 74 | "space-unary-ops": [2, { "words": true, "nonwords": false }], 75 | "strict": [2, "global"], 76 | "yoda": [2, "never"], 77 | "mocha/no-exclusive-tests": 2 78 | }, 79 | "plugins": [ 80 | "mocha" 81 | ] 82 | } 83 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vscode/ 3 | .DS_Store 4 | node_modules/ 5 | npm-debug.log 6 | todo.md 7 | /**/.build 8 | /recipes/**/wwwroot 9 | /recipes/**/bower_components -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - "stable" 5 | - "6" 6 | - "5" 7 | - "4" 8 | - "0.12" 9 | - "0.10" 10 | before_install: 11 | - npm install -g npm@next 12 | matrix: 13 | fast_finish: true 14 | allow_failures: 15 | - node_js: "0.10" 16 | - node_js: "0.12" 17 | -------------------------------------------------------------------------------- /.verb.md: -------------------------------------------------------------------------------- 1 | # Assemble recipes {%= badge("fury") %} {%= badge("travis") %} 2 | 3 | > {%= description %} 4 | 5 | ## Recipes 6 | 7 | All recipes contain some explanation but also a fully working version of the recipe in the according folder. 8 | 9 | - [Assemble & BrowserSync](recipes/browser-sync) 10 | - [Working with collections](recipes/collection-basic) 11 | - [Default layout](recipes/default-layout) 12 | - [Drafts](recipes/drafts) 13 | - [Gulp sitemap](recipes/gulp-sitemap) 14 | - [Less to CSS](recipes/less) 15 | - [Loading handlebar helpers](recipes/loading-handlebar-helpers) 16 | - [Permalinks](recipes/permalinks) 17 | - [Permalinks - Folder per file](recipes/permalinks-folder-per-file) 18 | - [Permalinks with subfolders/images](recipes/permalinks-copy-images) 19 | - [Events to hook into with middleware](recipes/middleware) 20 | - [Middleware example: Bind TOC to view](recipes/middleware-page-toc) 21 | - [Visual Studio Integration: Basic Bootstrap Site](recipes/visual-studio-integration) 22 | - [VS Code](recipes/vscode-integration) 23 | 24 | ## Running tests 25 | {%= include("tests") %} 26 | 27 | ## Contributing 28 | {%= include("contributing") %} 29 | 30 | ## Author 31 | {%= docs("author") %} 32 | 33 | ## License 34 | {%= copyright() %} 35 | {%= license %} 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Assemble recipes [![NPM version](https://img.shields.io/npm/v/assemble-workshop.svg?style=flat)](https://www.npmjs.com/package/assemble-workshop) [![Build Status](https://img.shields.io/travis/Stefan%20Walther/assemble-workshop.svg?style=flat)](https://travis-ci.org/Stefan%20Walther/assemble-workshop) 2 | 3 | > Some recipes using assemble v0.16.0. 4 | 5 | ## Recipes 6 | 7 | All recipes contain some explanation but also a fully working version of the recipe in the according folder. 8 | 9 | - [Assemble & BrowserSync](recipes/browser-sync) 10 | - [Working with collections](recipes/collection-basic) 11 | - [Default layout](recipes/default-layout) 12 | - [Drafts](recipes/drafts) 13 | - [Gulp sitemap](recipes/gulp-sitemap) 14 | - [Less to CSS](recipes/less) 15 | - [Loading handlebar helpers](recipes/loading-handlebar-helpers) 16 | - [Permalinks](recipes/permalinks) 17 | - [Permalinks - Folder per file](recipes/permalinks-folder-per-file) 18 | - [Permalinks with subfolders/images](recipes/permalinks-copy-images) 19 | - [Events to hook into with middleware](recipes/middleware) 20 | - [Middleware example: Bind TOC to view](recipes/middleware-page-toc) 21 | - [Visual Studio Integration: Basic Bootstrap Site](recipes/visual-studio-integration) 22 | - [VS Code](recipes/vscode-integration) 23 | 24 | ## Running tests 25 | Install dev dependencies: 26 | 27 | ```sh 28 | $ npm install -d && npm test 29 | ``` 30 | 31 | ## Contributing 32 | Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](../../issues/new). 33 | 34 | ## Author 35 | **Stefan Walther** 36 | 37 | * [qliksite.io](http://qliksite.io) 38 | * [twitter/waltherstefan](http://twitter.com/waltherstefan) 39 | * [github.com/stefanwalther](http://github.com/stefanwalther) 40 | 41 | ## License 42 | Copyright © 2016, Stefan Walther. 43 | Released under the MIT license. 44 | 45 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # Test against this version of Node.js 2 | environment: 3 | matrix: 4 | # node.js 5 | - nodejs_version: "6.0" 6 | - nodejs_version: "5.0" 7 | - nodejs_version: "4.0" 8 | - nodejs_version: "0.12" 9 | - nodejs_version: "0.10" 10 | 11 | # Configure matrix failures 12 | matrix: 13 | fast_finish: true 14 | allow_failures: 15 | - nodejs_version: "0.12" 16 | - nodejs_version: "0.10" 17 | 18 | # Install scripts. (runs after repo cloning) 19 | install: 20 | # Get the latest stable version of Node.js or io.js 21 | - ps: Install-Product node $env:nodejs_version 22 | # install modules 23 | - npm install 24 | 25 | # Post-install test scripts. 26 | test_script: 27 | # Output useful info for debugging. 28 | - node --version 29 | - npm --version 30 | # run tests 31 | - npm test 32 | 33 | # Don't actually build. 34 | build: off 35 | -------------------------------------------------------------------------------- /docs/author.md: -------------------------------------------------------------------------------- 1 | **Stefan Walther** 2 | 3 | * [qliksite.io](http://qliksite.io) 4 | * [twitter/waltherstefan](http://twitter.com/waltherstefan) 5 | * [github.com/stefanwalther](http://github.com/stefanwalther) -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "assemble-workshop", 3 | "version": "0.7.3", 4 | "description": "Some recipes using assemble v0.16.0.", 5 | "keywords": [ 6 | "assemble", 7 | "demos", 8 | "recipes", 9 | "samples", 10 | "workshop" 11 | ], 12 | "homepage": "https://github.com/assemble/assemble-workshop#readme", 13 | "bugs": { 14 | "url": "https://github.com/assemble/assemble-workshop/issues" 15 | }, 16 | "license": "MIT", 17 | "author": { 18 | "name": "Stefan Walther", 19 | "url": "https://github.com/stefanwalther" 20 | }, 21 | "main": "", 22 | "repository": { 23 | "type": "git", 24 | "url": "git+https://github.com/assemble/assemble-workshop.git" 25 | }, 26 | "scripts": { 27 | "eslint": "node node_modules/eslint/bin/eslint recipes", 28 | "test": "mocha ./recipes/**/*.spec.js" 29 | }, 30 | "dependencies": { 31 | "assemble": "github:assemble/assemble", 32 | "assemble-permalinks": "^0.5.0", 33 | "base-watch": "^0.1.3", 34 | "browser-sync": "^2.13.0", 35 | "debug": "^2.2.0", 36 | "del": "^2.2.1", 37 | "export-files": "^2.1.1", 38 | "fs-extra": "^0.30.0", 39 | "glob": "^7.0.5", 40 | "gulp": "^3.9.1", 41 | "gulp-cssnano": "^2.1.2", 42 | "gulp-drafts": "^0.2.0", 43 | "gulp-extname": "^0.2.2", 44 | "gulp-less": "^3.1.0", 45 | "gulp-sitemap": "^4.1.1", 46 | "gulp-sourcemaps": "^1.6.0", 47 | "helper-markdown": "^0.2.1", 48 | "markdown-toc": "^0.12.15", 49 | "slug": "^0.9.1" 50 | }, 51 | "devDependencies": { 52 | "chai": "^3.5.0", 53 | "chai-files": "^1.4.0", 54 | "eslint": "^3.1.1", 55 | "eslint-plugin-mocha": "^4.2.0", 56 | "mocha": "^2.5.3", 57 | "sinon": "^1.17.5", 58 | "sinon-chai": "^2.8.0" 59 | }, 60 | "engines": { 61 | "node": ">=0.10.0" 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /recipes/browser-sync/README.md: -------------------------------------------------------------------------------- 1 | # Assemble and Browser-Sync 2 | 3 | > This recipe uses assemble and [browser-sync](https://www.browsersync.io/) to both serve the files but also update the served files if needed. 4 | 5 | ## Purpose of this recipe 6 | - Convert some .less files to a single style sheet (.css file). 7 | - Convert some markdown files to html output, containing also a link to the generated CSS file. 8 | - Serve the files in the local browser automatically 9 | - Create some watchers on 10 | - all .less files (`./less` folder) 11 | - all content files (`./content` folder 12 | - In case any watcher is triggered, update either the stylesheets or the generated html files. 13 | 14 | **Main file:** 15 | ```js 16 | 'use strict'; 17 | var assemble = require( 'assemble' ); 18 | var extname = require( 'gulp-extname' ); 19 | var less = require( 'gulp-less' ); 20 | var browserSync = require( 'browser-sync' ).create(); 21 | var path = require( 'path' ); 22 | 23 | var app = assemble(); 24 | 25 | app.task( 'init', function ( cb ) { 26 | app.helper('markdown', require('helper-markdown')); 27 | app.layouts( './templates/layouts/**/*.hbs' ); 28 | cb(); 29 | } ); 30 | 31 | app.task( 'css', function () { 32 | return app.src( './less/default.less' ) 33 | .pipe( less() ) 34 | .pipe( app.dest( './.build/css' ) ) 35 | .pipe( browserSync.stream() ) 36 | } ); 37 | 38 | app.task( 'serve', function () { 39 | browserSync.init( { 40 | port: 8080, 41 | startPath: 'page-1.html', 42 | server: { 43 | baseDir: './.build' 44 | } 45 | } ) 46 | } ); 47 | 48 | app.task( 'content', ['init'], function () { 49 | return app.pages.src( './content/**/*.{md,hbs}' ) 50 | .pipe( app.renderFile() ) 51 | .on( 'err', console.error ) 52 | .pipe( extname() ) 53 | .pipe( app.dest( './.build' ) ) 54 | .pipe(browserSync.stream()); 55 | } ); 56 | 57 | app.task( 'default', ['css', 'content', 'serve'], function () { 58 | } ); 59 | 60 | app.watch( './content/**/*.md', ['content']); 61 | app.watch( './less/**/*.less', ['css']); 62 | 63 | module.exports = app; 64 | ``` 65 | 66 | **less/default.less** 67 | ```css 68 | @import "typography.less"; 69 | @import "variables.less"; 70 | ``` 71 | 72 | **less/typography.less** 73 | ```css 74 | html, body { 75 | font-family: @defaultFont; 76 | color: @mainColor; 77 | } 78 | 79 | h1 { 80 | color: @secondColor; 81 | } 82 | ``` 83 | 84 | **less/variables.less** 85 | ```css 86 | @mainColor: #666; 87 | @defaultFont: Arial, "Helvetica Neue", Helvetica, sans-serif; 88 | ``` 89 | 90 | **templates/layouts/default.hbs** 91 | ```html 92 | 93 | 94 | 95 | 96 | {{title}} 97 | 98 | 99 | 100 |

{{title}}

101 | {{#markdown}} 102 | {% body %} 103 | {{/markdown}} 104 | 105 | 106 | ``` 107 | 108 | **content/page-1.md** 109 | ``` 110 | --- 111 | title: Page 1 112 | layout: default 113 | --- 114 | This is the content of page 1 115 | ``` 116 | -------------------------------------------------------------------------------- /recipes/browser-sync/content/page-1.md: -------------------------------------------------------------------------------- 1 | title: Page 1 2 | --- 3 | This is the content of page 1 -------------------------------------------------------------------------------- /recipes/browser-sync/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var assemble = require( 'assemble' ); 3 | var extname = require( 'gulp-extname' ); 4 | var less = require( 'gulp-less' ); 5 | var browserSync = require( 'browser-sync' ).create(); 6 | var path = require( 'path' ); 7 | var watch = require( 'base-watch' ); 8 | 9 | var app = assemble(); 10 | app.use( watch() ); 11 | app.option( 'layout', 'default' ); 12 | 13 | app.task( 'init', function ( cb ) { 14 | app.helper( 'markdown', require( 'helper-markdown' ) ); 15 | app.layouts( path.join( __dirname, './templates/layouts/**/*.hbs' ) ); 16 | cb(); 17 | } ); 18 | 19 | app.task( 'css', function () { 20 | return app.src( path.join( __dirname, './less/default.less' ) ) 21 | .pipe( less() ) 22 | .pipe( app.dest( path.join( __dirname, './.build/css' ) ) ) 23 | .pipe( browserSync.stream() ); 24 | } ); 25 | 26 | app.task( 'serve', function () { 27 | browserSync.init( { 28 | port: 8080, 29 | startPath: 'page-1.html', 30 | server: { 31 | baseDir: path.join( __dirname, './.build' ) 32 | } 33 | } ); 34 | } ); 35 | 36 | app.task( 'content', ['init'], function () { 37 | return app.pages.src( path.join( __dirname, './content/**/*.{md,hbs}' ) ) 38 | .pipe( app.renderFile() ) 39 | .on( 'err', console.error ) 40 | .pipe( extname() ) 41 | .pipe( app.dest( path.join( __dirname, './.build' ) ) ) 42 | .pipe( browserSync.stream() ); 43 | } ); 44 | 45 | app.task( 'default', 46 | [ 47 | 'css', 48 | 'content', 49 | 'serve' 50 | ], function () { 51 | } ); 52 | 53 | app.watch( path.join( __dirname, './content/**/*.md' ), ['content'] ); 54 | app.watch( path.join( __dirname, './less/**/*.less' ), ['css'] ); 55 | 56 | module.exports = app; 57 | -------------------------------------------------------------------------------- /recipes/browser-sync/less/default.less: -------------------------------------------------------------------------------- 1 | @import "typography.less"; 2 | @import "variables.less"; -------------------------------------------------------------------------------- /recipes/browser-sync/less/typography.less: -------------------------------------------------------------------------------- 1 | html, body { 2 | font-family: @defaultFont; 3 | color: @mainColor; 4 | } 5 | 6 | h1 { 7 | color: @secondColor; 8 | } -------------------------------------------------------------------------------- /recipes/browser-sync/less/variables.less: -------------------------------------------------------------------------------- 1 | @mainColor: #666; 2 | @defaultFont: Arial, "Helvetica Neue", Helvetica, sans-serif; 3 | @secondColor: #333; -------------------------------------------------------------------------------- /recipes/browser-sync/run.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var app = require( './index' ); 3 | 4 | app.build( 'default', function ( err ) { 5 | if ( err ) { 6 | console.error( 'ERROR', err ); 7 | } 8 | } ); 9 | -------------------------------------------------------------------------------- /recipes/browser-sync/templates/layouts/default.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{title}} 6 | 7 | 8 | 9 |

{{title}}

10 | {{#markdown}} 11 | {% body %} 12 | {{/markdown}} 13 | 14 | -------------------------------------------------------------------------------- /recipes/collection-basic/README.md: -------------------------------------------------------------------------------- 1 | ## Working with collections 2 | 3 | **Purpose of this recipe** 4 | 5 | - Create a two collections, `articles` and `pages` 6 | - Render each file in the collections 7 | - Make the collections available for all files 8 | - Create a list in each file, containing a list using the own and the other collection ("List of all pages", "List of all articles") -------------------------------------------------------------------------------- /recipes/collection-basic/content/articles/article-1.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Article 1 3 | abstract: "This is the abstract of article 1" 4 | layout: default 5 | --- 6 | This is {{title}} -------------------------------------------------------------------------------- /recipes/collection-basic/content/articles/article-2.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Article 2 3 | abstract: "This is the abstract of article 2" 4 | layout: default 5 | --- 6 | This is {{title}} -------------------------------------------------------------------------------- /recipes/collection-basic/content/pages/page-1.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Page 1 3 | abstract: "This is the abstract of page 1" 4 | layout: default 5 | --- 6 | This is {{title}} -------------------------------------------------------------------------------- /recipes/collection-basic/content/pages/page-2.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Page 2 3 | abstract: "This is the abstract of page 2" 4 | layout: default 5 | --- 6 | This is {{title}} -------------------------------------------------------------------------------- /recipes/collection-basic/helpers/ctx.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function ( context ) { 4 | console.log( '------------------------------------------------------' ); 5 | console.info( 'ARGUMENTS:' ); 6 | console.log( arguments ); 7 | console.log( '------------------------------------------------------' ); 8 | console.info( 'CONTEXT:' ); 9 | console.log( context ); // the object passed to the helper 10 | console.log( '------------------------------------------------------' ); 11 | console.info( 'CONTEXT.HASH:' ); 12 | console.log( context.hash ); // hash arguments, like `foo='bar'` 13 | console.log( '------------------------------------------------------' ); 14 | console.info( 'THIS:' ); 15 | console.log( this ); // handlebars context 16 | console.log( '------------------------------------------------------' ); 17 | console.info( 'THIS.OPTIONS:' ); 18 | console.log( this.options ); // assemble `options` 19 | console.log( '------------------------------------------------------' ); 20 | console.info( 'THIS.CONTEXT:' ); 21 | console.log( this.context ); // context of the current 'view' 22 | console.log( '------------------------------------------------------' ); 23 | console.info( 'THIS.APP:' ); 24 | console.log( this.app ); // assemble instance 25 | }; 26 | -------------------------------------------------------------------------------- /recipes/collection-basic/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var assemble = require( 'assemble' ); 3 | var extname = require( 'gulp-extname' ); 4 | var path = require( 'path' ); 5 | 6 | var app = assemble(); 7 | 8 | app.create( 'articles' ); 9 | // No need to create the collection pages; `pages` is a default collection in assemble 10 | 11 | app.task( 'init', function ( cb ) { 12 | app.helper( 'ctx', path.join( __dirname, './helpers/ctx.js' ) ); 13 | app.layouts( path.join( __dirname, './templates/layouts/*.hbs' ) ); 14 | app.articles( path.join( __dirname, './content/articles/**/*.{md,hbs}' ) ); 15 | app.pages( path.join( __dirname, './content/pages/**/*.{md,hbs}' ) ); 16 | cb(); 17 | } ); 18 | 19 | app.preRender( /./, function ( view, next ) { 20 | view.data.articles = app.views.articles; 21 | view.data.pages = app.views.pages; 22 | next(); 23 | } ); 24 | 25 | app.task( 'content:articles', ['init'], function () { 26 | return app.toStream( 'articles' ) 27 | .on( 'err', console.error ) 28 | .pipe( app.renderFile() ) 29 | .on( 'err', console.error ) 30 | .pipe( extname() ) 31 | .pipe( app.dest( path.join( __dirname, './.build' ) ) ); 32 | } ); 33 | 34 | app.task( 'content:pages', ['init'], function () { 35 | return app.toStream( 'pages' ) 36 | .on( 'err', console.error ) 37 | .pipe( app.renderFile() ) 38 | .on( 'err', console.error ) 39 | .pipe( extname() ) 40 | .pipe( app.dest( path.join( __dirname, './.build' ) ) ); 41 | } ); 42 | 43 | app.task( 'default', ['content:articles', 'content:pages'] ); 44 | 45 | module.exports = app; 46 | -------------------------------------------------------------------------------- /recipes/collection-basic/index.spec.js: -------------------------------------------------------------------------------- 1 | /*global require*/ 2 | /*eslint no-unused-expressions:0*/ 3 | 'use strict'; 4 | var chai = require( 'chai' ); 5 | var expect = chai.expect; 6 | var path = require( 'path' ); 7 | var chaiFiles = require( 'chai-files' ); 8 | var utils = require( './../lib/test-utils' ); 9 | 10 | chai.use( chaiFiles ); 11 | 12 | var file = chaiFiles.file; 13 | var app = require( './index' ); 14 | 15 | describe( 'Collection Basic', function () { 16 | 17 | var delPath = path.join( __dirname, './.build' ); 18 | 19 | beforeEach( function ( cb ) { 20 | utils.clean( delPath, cb ); 21 | } ); 22 | 23 | afterEach( function ( cb ) { 24 | utils.clean( delPath, cb ); 25 | } ); 26 | 27 | // Skipping test for now, getting the following error: "Uncaught Error: no writecb in Transform class" 28 | xit( 'should succeed', function ( done ) { 29 | app.build( ['default'], function ( err ) { 30 | 31 | expect( err ).to.not.exist; 32 | 33 | var filePath = path.join( __dirname, './.build/article-1.html' ); 34 | expect( file( filePath ) ).to.exist; 35 | expect( file( filePath ) ).to.contain( 'This is the abstract of article 1' ); 36 | 37 | filePath = path.join( __dirname, './.build/article-2.html' ); 38 | expect( file( filePath ) ).to.exist; 39 | 40 | filePath = path.join( __dirname, './.build/page-1.html' ); 41 | expect( file( filePath ) ).to.exist; 42 | 43 | filePath = path.join( __dirname, './.build/page-2.html' ); 44 | expect( file( filePath ) ).to.exist; 45 | 46 | // Just a negative test to ensure that assertion works correctly. 47 | expect( file( path.join( __dirname, './.build/page-3.html' ) ) ).to.not.exist; 48 | done(); 49 | } ); 50 | } ); 51 | } ); 52 | -------------------------------------------------------------------------------- /recipes/collection-basic/templates/layouts/default.hbs: -------------------------------------------------------------------------------- 1 | # {{title}} 2 | 3 | {% body %} 4 | 5 | --- 6 | 7 | {{abstract}} 8 | 9 | --- 10 | All articles: 11 | 16 | 17 | All pages: 18 | 23 | -------------------------------------------------------------------------------- /recipes/default-layout/README.md: -------------------------------------------------------------------------------- 1 | ## Default layout 2 | 3 | > This recipe demonstrates how to define or force a default layout. 4 | 5 | **Setting the layout manually:** 6 | 7 | The layout for each document can be set in the front matter yml: 8 | 9 | ``` 10 | --- 11 | title: Some amazing title 12 | layout: whatever-layout 13 | --- 14 | ``` 15 | 16 | **Defining a default layout:** 17 | 18 | If you want to define a default layout for the entire app, first set the global option `layout`: 19 | 20 | ``` 21 | app.option('layout', 'whatever-layout'); 22 | ``` 23 | 24 | Then use some middleware to set the default layout if not explicitly defined in the current document: 25 | 26 | ```js 27 | app.preLayout( /./, function ( view, next ) { 28 | // if the layout is not defined, use the default one ... 29 | if (!view.layout && app.options.layout) { 30 | view.layout = app.options.layout; 31 | } 32 | next(); 33 | } ); 34 | ``` 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /recipes/default-layout/content/explicit.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Explicit 3 | layout: the-special-one 4 | --- 5 | {{title}} -------------------------------------------------------------------------------- /recipes/default-layout/content/implicit.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Implicit 3 | --- 4 | {{title}} -------------------------------------------------------------------------------- /recipes/default-layout/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var assemble = require( 'assemble' ); 3 | var path = require( 'path' ); 4 | 5 | var app = assemble(); 6 | 7 | app.option( 'layout', 'the-special-one' ); 8 | app.preLayout( /./, function ( view, next ) { 9 | // if the layout is not defined, use the default one ... 10 | if ( !view.layout && app.options.layout ) { 11 | view.layout = app.options.layout; 12 | } 13 | next(); 14 | } ); 15 | 16 | app.task( 'init', function ( cb ) { 17 | app.helper( 'markdown', require( 'helper-markdown' ) ); 18 | app.layouts( path.join( __dirname, './templates/layouts/**/*.hbs' ) ); 19 | cb(); 20 | } ); 21 | 22 | app.task( 'default', ['init'], function () { 23 | return app.pages.src( path.join( __dirname, './content/**/*.{md,hbs}' ) ) 24 | .pipe( app.renderFile() ) 25 | .pipe( app.dest( path.join( __dirname, './.build' ) ) ); 26 | } ); 27 | 28 | module.exports = app; 29 | 30 | 31 | -------------------------------------------------------------------------------- /recipes/default-layout/index.spec.js: -------------------------------------------------------------------------------- 1 | /*eslint no-unused-expressions:0*/ 2 | 'use strict'; 3 | var chai = require( 'chai' ); 4 | var expect = chai.expect; 5 | var path = require( 'path' ); 6 | var chaiFiles = require( 'chai-files' ); 7 | var utils = require( './../lib/test-utils' ); 8 | 9 | chai.use( chaiFiles ); 10 | var file = chaiFiles.file; 11 | var app = require( './index' ); 12 | 13 | describe( 'default-layout', function () { 14 | 15 | var delPath = path.join( __dirname, './.build' ); 16 | beforeEach( function ( cb ) { 17 | utils.clean( delPath, cb ); 18 | } ); 19 | afterEach( function ( cb ) { 20 | utils.clean( delPath, cb ); 21 | } ); 22 | 23 | it( 'should be effective', function ( done ) { 24 | app.build( 'default', function ( err ) { 25 | expect( err ).to.not.exist; 26 | expect( file( path.join( __dirname, './.build/explicit.md' ) ) ).to.match( /This is the special layout/ ); 27 | expect( file( path.join( __dirname, './.build/implicit.md' ) ) ).to.match( /This is the special layout/ ); 28 | done(); 29 | } ); 30 | } ); 31 | } ); 32 | -------------------------------------------------------------------------------- /recipes/default-layout/templates/layouts/default.hbs: -------------------------------------------------------------------------------- 1 | The default layout. 2 | 3 | {% body %} -------------------------------------------------------------------------------- /recipes/default-layout/templates/layouts/the-special-one.hbs: -------------------------------------------------------------------------------- 1 | This is the special layout. 2 | 3 | {% body %} -------------------------------------------------------------------------------- /recipes/drafts/README.md: -------------------------------------------------------------------------------- 1 | ## Working with drafts 2 | 3 | Two different approaches are used in this recipe: 4 | 5 | - Using the plugin `gulp-drafts` 6 | - Using a custom plugin (`./templates/plugins/drafts.js` 7 | 8 | ### Usage 9 | 10 | - Mark documents in the front matter as draft to prevent them from being rendered. 11 | -------------------------------------------------------------------------------- /recipes/drafts/content/default.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Default 3 | --- 4 | {{title}} -------------------------------------------------------------------------------- /recipes/drafts/content/draft-false.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Draft false 3 | draft: false 4 | --- 5 | {{title}} -------------------------------------------------------------------------------- /recipes/drafts/content/draft-true.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Draft true 3 | draft: true 4 | --- 5 | {{title}} -------------------------------------------------------------------------------- /recipes/drafts/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var assemble = require( 'assemble' ); 3 | var path = require( 'path' ); 4 | var gulpDrafts = require( 'gulp-drafts' ); 5 | var pluginDrafts = require( './plugins/drafts' ); 6 | var app = assemble(); 7 | 8 | var paths = { 9 | srcDir: path.join( __dirname, './content/**/*.{md,hbs}' ), 10 | buildDir: path.join( __dirname, './.build' ) 11 | }; 12 | 13 | app.pages( paths.srcDir ); 14 | 15 | app.task( 'gulp-draft', function () { 16 | return app.pages.toStream() 17 | .on( 'err', console.error ) 18 | .pipe( gulpDrafts() ) 19 | .pipe( app.renderFile() ) 20 | .on( 'err', console.error ) 21 | .pipe( app.dest( paths.buildDir ) ); 22 | } ); 23 | 24 | app.task( 'draft-plugin', function () { 25 | 26 | app.use( pluginDrafts( 'pages' ) ); 27 | 28 | return app.pages.toStream() 29 | .on( 'error', console.error ) 30 | .pipe( app.renderFile() ) 31 | .on( 'error', console.error ) 32 | .pipe( app.dest( paths.buildDir ) ); 33 | 34 | } ); 35 | 36 | module.exports = app; 37 | -------------------------------------------------------------------------------- /recipes/drafts/index.spec.js: -------------------------------------------------------------------------------- 1 | /*eslint no-unused-expressions:0*/ 2 | 'use strict'; 3 | var chai = require( 'chai' ); 4 | var expect = chai.expect; 5 | var path = require( 'path' ); 6 | var chaiFiles = require( 'chai-files' ); 7 | var utils = require( './../lib/test-utils' ); 8 | 9 | chai.use( chaiFiles ); 10 | var file = chaiFiles.file; 11 | var app = require( './index' ); 12 | 13 | describe( 'drafts', function () { 14 | 15 | var delPath = path.join( __dirname, './.build' ); 16 | beforeEach( function ( cb ) { 17 | utils.clean( delPath, cb ); 18 | } ); 19 | afterEach( function ( cb ) { 20 | utils.clean( delPath, cb ); 21 | } ); 22 | 23 | it( 'using gulp-drafts: renders only non-draft files.', function ( done ) { 24 | app.build( 'gulp-draft', function ( err ) { 25 | expect( err ).to.not.exist; 26 | expect( file( path.join( __dirname, './.build/default.md' ) ) ).to.contain( 'Default' ); 27 | expect( file( path.join( __dirname, './.build/draft-false.md' ) ) ).to.contain( 'Draft false' ); 28 | done(); 29 | } ); 30 | } ); 31 | 32 | it( 'using custom draft-plugin: renders only non-draft files.', function ( done ) { 33 | app.build( 'draft-plugin', function ( err ) { 34 | expect( err ).to.not.exist; 35 | expect( file( path.join( __dirname, './.build/default.md' ) ) ).to.contain( 'Default' ); 36 | expect( file( path.join( __dirname, './.build/draft-false.md' ) ) ).to.contain( 'Draft false' ); 37 | done(); 38 | } ); 39 | } ); 40 | } ); 41 | -------------------------------------------------------------------------------- /recipes/drafts/plugins/drafts.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * Expose `plugin`. 4 | */ 5 | 6 | /** 7 | * Assemble plugin to remove files marked as `draft` from a collection. 8 | * 9 | * @return {Function} 10 | */ 11 | module.exports = function plugin ( name ) { 12 | return function ( app ) { 13 | var files = app.getViews( name ); 14 | for ( var file in files ) { 15 | if ( files[file].data.draft ) { 16 | delete files[file]; 17 | } 18 | } 19 | }; 20 | }; 21 | -------------------------------------------------------------------------------- /recipes/gulp-sitemap/README.md: -------------------------------------------------------------------------------- 1 | # Gulp Sitemap 2 | 3 | > Generate a sitemap for your assemble generated site. 4 | 5 | ## Generate some pages 6 | 7 | Here is a simple example of generating some html files from handle bars (.hbs) files. 8 | 9 | ```js 10 | 11 | 'use strict'; 12 | 13 | var app = require('assemble')(); 14 | var path = require('path'); 15 | var ext = require('gulp-extname'); 16 | 17 | app.option('layout', 'default'); 18 | app.layouts(path.join(__dirname, 'src/layouts/**/*.hbs')); 19 | 20 | app.task('default', function () { 21 | 22 | //Here we are using a gulp plugin to replace the .hbs ext with .html for all the pages. 23 | return app.src('src/pages/**/*.hbs', { layout: 'default' }) 24 | .pipe(app.renderFile()) 25 | .pipe(ext())) 26 | .pipe(app.dest('wwwroot')); 27 | }); 28 | 29 | module.exports = app; 30 | 31 | ``` 32 | 33 | ## Generate a sitemap files 34 | 35 | Now that we have some html files generated, we need to include a sitemap for the bots. 36 | This can be done easily using a gulp plugin. This is possible beacause assemble supports 37 | can use any gulp plugin. So, we simply add the 38 | [gulp-sitemap](https://www.npmjs.com/package/gulp-sitemap) plugin, 39 | configure it will the sites base url and configure the tasks so that 40 | the sitemap is created after the pages generated. 41 | 42 | ```js 43 | 44 | 'use strict'; 45 | 46 | var app = require('assemble')(); 47 | var path = require('path'); 48 | var ext = require('gulp-extname'); 49 | var sitemap = require('gulp-sitemap'); 50 | 51 | app.option('layout', 'default'); 52 | app.layouts(path.join(__dirname, 'src/layouts/**/*.hbs')); 53 | 54 | app.task('pages', function () { 55 | 56 | //Here we are using a gulp plugin to replace the .hbs ext with .html for all the pages. 57 | return app.src('src/pages/**/*.hbs', { layout: 'default' }) 58 | .pipe(app.renderFile()) 59 | .pipe(ext()) 60 | .pipe(app.dest('wwwroot')); 61 | }); 62 | 63 | 64 | app.task('default', ['pages'], function () { 65 | 66 | //Here we are using a gulp plugin to generate a sitemap for the files generated by the pages task. 67 | return app.src('wwwroot/**/*.html') 68 | .pipe(sitemap({ 69 | siteUrl: 'http://whatever.site' 70 | })) 71 | .pipe(app.dest('wwwroot')); 72 | }); 73 | 74 | 75 | module.exports = app; 76 | 77 | ``` -------------------------------------------------------------------------------- /recipes/gulp-sitemap/assemblefile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var app = require('assemble')(); 4 | var path = require('path'); 5 | var ext = require('gulp-extname'); 6 | var sitemap = require('gulp-sitemap'); 7 | 8 | app.option('layout', 'default'); 9 | app.layouts(path.join(__dirname, 'src/layouts/**/*.hbs')); 10 | 11 | app.task('pages', function () { 12 | 13 | //Here we are using a gulp plugin to replace the .hbs ext with .html for all the pages. 14 | return app.src(path.join(__dirname, 'src/pages/**/*.hbs'), { layout: 'default' }) 15 | .pipe(app.renderFile()) 16 | .pipe(ext()) 17 | .pipe(app.dest(path.join(__dirname, 'wwwroot'))); 18 | }); 19 | 20 | 21 | app.task('default', ['pages'], function () { 22 | 23 | //Here we are using a gulp plugin to generate a sitemap for the files generated by the pages task. 24 | return app.src(path.join(__dirname, 'wwwroot/**/*.html')) 25 | .pipe(sitemap({ 26 | siteUrl: 'http://whatever.site' 27 | })) 28 | .pipe(app.dest(path.join(__dirname, 'wwwroot'))); 29 | }); 30 | 31 | 32 | module.exports = app; -------------------------------------------------------------------------------- /recipes/gulp-sitemap/assemblefile.spec.js: -------------------------------------------------------------------------------- 1 | /*eslint no-unused-expressions:0*/ 2 | 'use strict'; 3 | var chai = require( 'chai' ); 4 | var expect = chai.expect; 5 | var path = require( 'path' ); 6 | var chaiFiles = require( 'chai-files' ); 7 | var utils = require( './../lib/test-utils' ); 8 | 9 | chai.use( chaiFiles ); 10 | var file = chaiFiles.file; 11 | var app = require( './assemblefile' ); 12 | 13 | describe( 'Gulp-sitemap using Assemble', function () { 14 | 15 | var delPath = path.join( __dirname, './wwwroot' ); 16 | beforeEach( function ( cb ) { 17 | utils.clean( delPath, cb ); 18 | } ); 19 | afterEach( function ( cb ) { 20 | utils.clean( delPath, cb ); 21 | } ); 22 | 23 | it( 'creates a three html files from hbs files in src/pages', function ( done ) { 24 | app.build( 'pages', function ( err ) { 25 | expect( err ).to.not.exist; 26 | expect( file ( path.join( __dirname, './wwwroot/index.html' ) ) ).to.exist; 27 | expect( file ( path.join( __dirname, './wwwroot/about.html' ) ) ).to.exist; 28 | expect( file ( path.join( __dirname, './wwwroot/contact.html' ) ) ).to.exist 29 | done(); 30 | } ); 31 | } ); 32 | 33 | it( 'creates a stemap.xml file', function ( done ) { 34 | app.build( 'default', function ( err ) { 35 | expect( err ).to.not.exist; 36 | 37 | var p = path.join( __dirname, './wwwroot/sitemap.xml' ); 38 | expect( file ( p ) ).to.exist; 39 | expect( file ( p ) ).to.match( /urlset/ ); 40 | done(); 41 | } ); 42 | } ); 43 | } ); 44 | -------------------------------------------------------------------------------- /recipes/gulp-sitemap/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "assemble-site-template", 3 | "version": "1.0.0", 4 | "description": "", 5 | "devDependencies": { 6 | "assemble": "^0.12.0", 7 | "gulp": "^3.9.1", 8 | "gulp-extname" : "^0.2.2", 9 | "gulp-sitemap": "^4.1.1" 10 | }, 11 | "author": "ITLackey", 12 | "license": "ISC" 13 | } 14 | -------------------------------------------------------------------------------- /recipes/gulp-sitemap/src/layouts/default.hbs: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 9 |
10 | {% body %} 11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /recipes/gulp-sitemap/src/pages/about.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | title: About 3 | layout: default 4 | --- 5 | About page -------------------------------------------------------------------------------- /recipes/gulp-sitemap/src/pages/contact.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | title: Contact Us 3 | layout: default 4 | --- 5 | Contact page -------------------------------------------------------------------------------- /recipes/gulp-sitemap/src/pages/index.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | title: Home 3 | layout: default 4 | --- 5 | Home page -------------------------------------------------------------------------------- /recipes/less/README.md: -------------------------------------------------------------------------------- 1 | # Less to CSS 2 | 3 | > Convert your .less files to .css files using assemble and several Gulp plugins. 4 | 5 | ## Convert from .less to .css 6 | 7 | The beauty of assemble is that you can use any Gulp plugin. So converting .less files to .css files is pretty easy using [gulp-less](https://www.npmjs.com/package/gulp-less): 8 | 9 | ```js 10 | var assemble = require( 'assemble' ); 11 | var less = require( 'gulp-less' ); 12 | var path = require( 'path' ); 13 | 14 | var app = assemble(); 15 | 16 | app.task( 'css', function () { 17 | return app.src( './less/default.less' ) 18 | .pipe( less() ) 19 | .pipe( app.dest( './.build/css' ) ); 20 | } ); 21 | 22 | module.exports = app; 23 | ``` 24 | 25 | ## Minification & Source Maps 26 | 27 | Based on the logic from above, let's use another two Gulp plugins to minify the css ([gulp-cssnano](https://www.npmjs.com/package/gulp-cssnano)) and to add source map support ([gulp-sourcemaps](https://www.npmjs.com/package/gulp-sourcemaps)): 28 | 29 | ```js 30 | var assemble = require( 'assemble' ); 31 | var less = require( 'gulp-less' ); 32 | var path = require( 'path' ); 33 | var nano = require( 'gulp-cssnano' ); 34 | var sourceMaps = require( 'gulp-sourcemaps' ); 35 | 36 | var app = assemble(); 37 | 38 | app.task( 'css:optimized', function () { 39 | 40 | var lessOptions = {}; 41 | var nanoOptions = {}; 42 | 43 | return app.src( './less/default.less' ) 44 | .pipe( sourceMaps.init() ) 45 | .pipe( less( lessOptions ) ) 46 | .pipe( nano( nanoOptions ) ) 47 | .pipe( sourceMaps.write() ) 48 | .pipe( app.dest( './.build/css' ) ); 49 | } ); 50 | 51 | module.exports = app; 52 | 53 | ``` 54 | -------------------------------------------------------------------------------- /recipes/less/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var assemble = require( 'assemble' ); 3 | var less = require( 'gulp-less' ); 4 | var path = require( 'path' ); 5 | var nano = require( 'gulp-cssnano' ); 6 | var sourceMaps = require( 'gulp-sourcemaps' ); 7 | 8 | var app = assemble(); 9 | 10 | app.task( 'css', function () { 11 | return app.src( path.join( __dirname, './less/default.less' ) ) 12 | .pipe( less() ) 13 | .pipe( app.dest( path.join( __dirname, './.build/css' ) ) ); 14 | } ); 15 | 16 | app.task( 'css:optimized', function () { 17 | 18 | // http://lesscss.org/#using-less-configuration 19 | var lessOptions = { 20 | compress: false // Let's cssnano do the job. 21 | }; 22 | 23 | // http://cssnano.co/optimisations/ 24 | var nanoOptions = { 25 | autoprefixer: false 26 | }; 27 | 28 | return app.src( path.join( __dirname, './less/default.less' ) ) 29 | .pipe( sourceMaps.init() ) 30 | .pipe( less( lessOptions ) ) 31 | .pipe( nano( nanoOptions ) ) 32 | .pipe( sourceMaps.write() ) 33 | .pipe( app.dest( path.join( __dirname, './.build/css' ) ) ); 34 | } ); 35 | 36 | module.exports = app; 37 | -------------------------------------------------------------------------------- /recipes/less/index.spec.js: -------------------------------------------------------------------------------- 1 | /*eslint no-unused-expressions:0*/ 2 | 'use strict'; 3 | var chai = require( 'chai' ); 4 | var expect = chai.expect; 5 | var path = require( 'path' ); 6 | var chaiFiles = require( 'chai-files' ); 7 | var utils = require( './../lib/test-utils' ); 8 | 9 | chai.use( chaiFiles ); 10 | var file = chaiFiles.file; 11 | var app = require( './index' ); 12 | 13 | describe( 'Less to css', function () { 14 | 15 | var delPath = path.join( __dirname, './.build' ); 16 | beforeEach( function ( cb ) { 17 | utils.clean( delPath, cb ); 18 | } ); 19 | afterEach( function ( cb ) { 20 | utils.clean( delPath, cb ); 21 | } ); 22 | 23 | it( 'creates a single file, merged from multiple less files', function ( done ) { 24 | app.build( 'css', function ( err ) { 25 | expect( err ).to.not.exist; 26 | expect( file( path.join( __dirname, './.build/css/default.css' ) ) ).to.exist; 27 | expect( file( path.join( __dirname, './.build/css/typography.css' ) ) ).to.not.exist; 28 | expect( file( path.join( __dirname, './.build/variables.css' ) ) ).to.not.exist; 29 | done(); 30 | } ); 31 | } ); 32 | 33 | it( 'creates a single file, minifies and includes sourcemap', function ( done ) { 34 | app.build( 'css:optimized', function ( err ) { 35 | expect( err ).to.not.exist; 36 | var p = path.join( __dirname, './.build/css/default.css' ); 37 | expect( file( p ) ).to.exist; 38 | expect( file( p ) ).to.match( /sourceMappingURL/ ); 39 | expect( file( p ) ).to.match( /body,html\{font-family:Arial,Helvetica Neue,Helvetica,sans-serif;color:#666}h1\{color:#333}/ ); 40 | 41 | expect( file( path.join( __dirname, './.build/css/typography.css' ) ) ).to.not.exist; 42 | expect( file( path.join( __dirname, './.build/variables.css' ) ) ).to.not.exist; 43 | done(); 44 | } ); 45 | } ); 46 | } ); 47 | -------------------------------------------------------------------------------- /recipes/less/less/default.less: -------------------------------------------------------------------------------- 1 | @import "typography.less"; 2 | @import "variables.less"; -------------------------------------------------------------------------------- /recipes/less/less/typography.less: -------------------------------------------------------------------------------- 1 | html, body { 2 | font-family: @defaultFont; 3 | color: @mainColor; 4 | } 5 | 6 | h1 { 7 | color: @secondColor; 8 | } -------------------------------------------------------------------------------- /recipes/less/less/variables.less: -------------------------------------------------------------------------------- 1 | @mainColor: #666; 2 | @defaultFont: Arial, "Helvetica Neue", Helvetica, sans-serif; 3 | @secondColor: #333; -------------------------------------------------------------------------------- /recipes/lib/test-utils.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var del = require( 'del' ); 3 | 4 | function clean ( delPath, cb ) { 5 | del( delPath ) 6 | .then( function () { 7 | cb(); 8 | } ); 9 | } 10 | 11 | module.exports.clean = clean; 12 | -------------------------------------------------------------------------------- /recipes/lib/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var path = require( 'path' ); 3 | 4 | module.exports = { 5 | stripExtension: function ( filepath, ext ) { 6 | ext = ext || path.extname( filepath ); 7 | var r = filepath.slice( 0, filepath.length - ext.length ); 8 | console.log( r ); 9 | return r; 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /recipes/loading-handlebar-helpers/README.md: -------------------------------------------------------------------------------- 1 | ## Loading handlebar helpers 2 | 3 | Example how to define and load handlebar helpers: 4 | 5 | ```js 6 | app.helpers( './helpers/*.js' ); 7 | ``` 8 | -------------------------------------------------------------------------------- /recipes/loading-handlebar-helpers/content/if_eq.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: if_q 3 | --- 4 | {{#if_q "a" "a"}} 5 | a==a 6 | {{/if_q}} 7 | -------------------------------------------------------------------------------- /recipes/loading-handlebar-helpers/content/if_eq_false.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: if_q 3 | --- 4 | {{#if_q "a" "b"}} 5 | a==a 6 | {{else}} 7 | a!=b 8 | {{/if_q}} 9 | -------------------------------------------------------------------------------- /recipes/loading-handlebar-helpers/content/test.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Content 1 3 | --- 4 | {{test}} 5 | -------------------------------------------------------------------------------- /recipes/loading-handlebar-helpers/helpers/if_q.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /*eslint camelcase: 0*/ 4 | module.exports = function if_q ( a, b, opts ) { 5 | 6 | if ( a === b ) { 7 | return opts.fn( this ); 8 | } else { 9 | return opts.inverse( this ); 10 | } 11 | 12 | }; 13 | -------------------------------------------------------------------------------- /recipes/loading-handlebar-helpers/helpers/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function test( /*opts*/ ) { 4 | 5 | return 'This is a test'; 6 | 7 | }; 8 | 9 | -------------------------------------------------------------------------------- /recipes/loading-handlebar-helpers/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var assemble = require( 'assemble' ); 3 | var path = require( 'path' ); 4 | 5 | var app = assemble(); 6 | 7 | app.helpers( path.join( __dirname, './helpers/*.js' ) ); 8 | 9 | app.task( 'default', function () { 10 | return app.pages.src( path.join( __dirname, './content/**/*.{md,hbs}' ) ) 11 | .pipe( app.renderFile() ) 12 | .pipe( app.dest( path.join( __dirname, './.build' ) ) ); 13 | } ); 14 | 15 | module.exports = app; 16 | 17 | -------------------------------------------------------------------------------- /recipes/loading-handlebar-helpers/index.spec.js: -------------------------------------------------------------------------------- 1 | /*eslint no-unused-expressions:0*/ 2 | 'use strict'; 3 | var chai = require( 'chai' ); 4 | var expect = chai.expect; 5 | var chaiFiles = require( 'chai-files' ); 6 | var path = require( 'path' ); 7 | var del = require( 'del' ); 8 | 9 | chai.use( chaiFiles ); 10 | var file = chaiFiles.file; 11 | var app = require( './index' ); 12 | 13 | describe( 'Helper', function () { 14 | 15 | after( function ( done ) { 16 | del( path.join( __dirname, './.build' ) ) 17 | .then( function () { 18 | done(); 19 | } ); 20 | //done(); 21 | } ); 22 | 23 | it( ' should resolve properly', function ( done ) { 24 | app.build( 'default', function ( err ) { 25 | expect( err ).to.not.exist; 26 | expect( file( path.join( __dirname, './.build/test.md' ) ) ).to.match( /This is a test/ ); 27 | done(); 28 | } ); 29 | } ); 30 | 31 | it( ' should resolve properly if condition is true', function ( done ) { 32 | app.build( 'default', function ( err ) { 33 | expect( err ).to.not.exist; 34 | expect( file( path.join( __dirname, './.build/if_eq.md' ) ) ).to.match( /a==a/ ); 35 | done(); 36 | } ); 37 | } ); 38 | 39 | it( ' should resolve properly if condition is false', function ( done ) { 40 | app.build( 'default', function ( err ) { 41 | expect( err ).to.not.exist; 42 | expect( file( path.join( __dirname, './.build/if_eq_false.md' ) ) ).to.match( /a!=b/ ); 43 | done(); 44 | } ); 45 | } ); 46 | 47 | } ); 48 | -------------------------------------------------------------------------------- /recipes/loading-handlebar-helpers/run.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var app = require( './index' ); 3 | 4 | app.build( ['default'], function ( err ) { 5 | if ( err ) { 6 | console.error( 'ERROR: ', err ); 7 | } 8 | } ); 9 | -------------------------------------------------------------------------------- /recipes/middleware-page-toc/README.md: -------------------------------------------------------------------------------- 1 | # Middleware to bind toc to view 2 | 3 | This recipe uses a middleware and markdown-toc to bind a table of contents to the view and then uses this data in the layout to render a specific table of contents. -------------------------------------------------------------------------------- /recipes/middleware-page-toc/content/article-1.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Article 1 3 | layout: default 4 | --- 5 | 6 | # Heading 1 7 | 8 | ## Heading 1.1 9 | 10 | # Heading 2 11 | 12 | ## Heading 2.1 13 | 14 | ## Heading 2.2 15 | 16 | ### Heading 2.2.1 17 | 18 | ### Heading 2.2.2 19 | 20 | ## Heading 2.3 21 | -------------------------------------------------------------------------------- /recipes/middleware-page-toc/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var assemble = require( 'assemble' ); 3 | var extname = require( 'gulp-extname' ); 4 | var toc = require( 'markdown-toc' ); 5 | var path = require( 'path' ); 6 | 7 | var app = assemble(); 8 | 9 | app.pages( path.join( __dirname, './content/**/*.{md,hbs}' ) ); 10 | app.layouts( path.join( __dirname, './templates/layouts/**/*.hbs' ) ); 11 | /** 12 | * Bind an object called `toc` to each view containing the table of contents using markdown-toc. 13 | */ 14 | app.preRender( /\.md/, function ( view, next ) { 15 | view.data.toc = toc( view._content ).json; //eslint-disable-line 16 | next(); 17 | } ); 18 | 19 | app.helper( 'markdown', require( 'helper-markdown' ) ); 20 | 21 | /** 22 | * Set the default layout for files with the extension .md or .hbs. 23 | */ 24 | app.preLayout( /\/content\/.*\.(md|hbs)/, function ( view, next ) { 25 | if ( !view.layout ) { 26 | view.layout = 'default'; 27 | } 28 | next(); 29 | } ); 30 | 31 | app.task( 'default', function () { 32 | return app.toStream( 'pages' ) 33 | .pipe( app.renderFile() ) 34 | .on( 'error', console.error ) 35 | .pipe( extname() ) 36 | .pipe( app.dest( path.join( __dirname, './.build' ) ) ); 37 | } ); 38 | 39 | module.exports = app; 40 | -------------------------------------------------------------------------------- /recipes/middleware-page-toc/index.spec.js: -------------------------------------------------------------------------------- 1 | /*eslint no-unused-expressions:0*/ 2 | 'use strict'; 3 | var chai = require( 'chai' ); 4 | var expect = chai.expect; 5 | var path = require( 'path' ); 6 | var utils = require( './../lib/test-utils' ); 7 | 8 | var app = require( './index' ); 9 | 10 | describe( 'Plugin Page-TOC', function () { 11 | 12 | var delPath = path.join( __dirname, './.build' ); 13 | beforeEach( function ( cb ) { 14 | utils.clean( delPath, cb ); 15 | } ); 16 | afterEach( function ( cb ) { 17 | utils.clean( delPath, cb ); 18 | } ); 19 | 20 | it( 'should succeed', function ( done ) { 21 | app.build( 'default', function ( err ) { 22 | expect( err ).to.not.exist; 23 | expect( app.pages.getView( path.join( __dirname, './content/article-1.md' ) ) ).to.exist; 24 | expect( app.pages.getView( path.join( __dirname, './content/article-1.md' ) ).data ).to.have.property( 'toc' ); 25 | expect( app.pages.getView( path.join( __dirname, './content/article-1.md' ) ).data.toc[0] ).to.have.property( 'slug' ); 26 | done(); 27 | } ); 28 | } ); 29 | } ); 30 | -------------------------------------------------------------------------------- /recipes/middleware-page-toc/run.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var app = require( './index' ); 3 | 4 | app.build( ['default'], function ( err ) { 5 | if ( err ) { 6 | console.error( 'ERROR: ', err ); 7 | } 8 | } ); 9 | -------------------------------------------------------------------------------- /recipes/middleware-page-toc/templates/layouts/default.hbs: -------------------------------------------------------------------------------- 1 | {{#markdown}} 2 | {% body %} 3 | {{/markdown}} 4 | --- 5 | Table of Contents: 6 | 7 | {{#each toc}} 8 | {{./content}}
9 | {{/each}} 10 | -------------------------------------------------------------------------------- /recipes/middleware/README.md: -------------------------------------------------------------------------------- 1 | ## Middleware events 2 | 3 | Events where you can hook into to create middleware logic. 4 | 5 | - preLayout 6 | - onLoad 7 | - preCompile 8 | - postCompile 9 | - preRender 10 | - postRender 11 | 12 | Example for a middleware to set the layout (if not already defined in the front matter): 13 | 14 | ```js 15 | app.preLayout( /./, function ( view, next ) { 16 | // if the layout is not defined, set it to a specific one ... 17 | if ( !view.layout ) { 18 | view.layout = 'whatever-layout'; 19 | } 20 | next(); 21 | } ); 22 | ``` -------------------------------------------------------------------------------- /recipes/middleware/content/page-1.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Page 1 3 | --- 4 | {{title}} -------------------------------------------------------------------------------- /recipes/middleware/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var assemble = require( 'assemble' ); 3 | var path = require( 'path' ); 4 | 5 | var app = assemble(); 6 | 7 | app.preLayout( /\.md/, function ( view, next ) { 8 | // console.log( view.data.title + ': preLayout', view ); 9 | next(); 10 | } ); 11 | 12 | app.onLoad( /\.md/, function ( view, next ) { 13 | // console.log( view.data.title + ': onLoad', view ); 14 | next(); 15 | } ); 16 | 17 | app.preCompile( /\.md/, function ( view, next ) { 18 | // console.log( view.data.title + ': preCompile', view ); 19 | next(); 20 | } ); 21 | 22 | app.postCompile( /\.md/, function ( view, next ) { 23 | // console.log( view.data.title + ': postCompile', view ); 24 | next(); 25 | } ); 26 | 27 | app.preRender( /\.md/, function ( view, next ) { 28 | // console.log( view.data.title + ': preRender', view ); 29 | next(); 30 | } ); 31 | 32 | app.postRender( /\.md/, function ( view, next ) { 33 | // console.log( view.data.title + ': postRender', view ); 34 | next(); 35 | } ); 36 | 37 | app.postWrite( /\.md/, function ( view, next ) { 38 | next(); 39 | } ); 40 | 41 | app.task( 'default', function () { 42 | return app.pages.src( path.join( __dirname, './content/**/*.{md,hbs}' ) ) 43 | .pipe( app.renderFile() ) 44 | .pipe( app.dest( path.join( __dirname, './.build' ) ) ); 45 | } ); 46 | 47 | module.exports = app; 48 | -------------------------------------------------------------------------------- /recipes/middleware/index.spec.js: -------------------------------------------------------------------------------- 1 | /*eslint no-unused-expressions:0*/ 2 | 'use strict'; 3 | var chai = require( 'chai' ); 4 | var expect = chai.expect; 5 | var sinonChai = require( 'sinon-chai' ); 6 | var sinon = require( 'sinon' ); 7 | var utils = require( './../lib/test-utils' ); 8 | var path = require( 'path' ); 9 | 10 | chai.use( sinonChai ); 11 | 12 | var app = require( './index' ); 13 | 14 | describe( 'middleware', function () { 15 | 16 | var delPath = path.join( __dirname, './.build' ); 17 | beforeEach( function ( cb ) { 18 | utils.clean( delPath, cb ); 19 | } ); 20 | afterEach( function ( cb ) { 21 | utils.clean( delPath, cb ); 22 | } ); 23 | 24 | it( 'events are emitted', function ( done ) { 25 | 26 | var spyOnLoad = sinon.spy(); 27 | app.on( 'onLoad', spyOnLoad ); 28 | 29 | var spyOnStream = sinon.spy(); 30 | app.on( 'onStream', spyOnStream ); 31 | 32 | var spyPreRender = sinon.spy(); 33 | app.on( 'preRender', spyPreRender ); 34 | 35 | var spyPreCompile = sinon.spy(); 36 | app.on( 'preCompile', spyPreCompile ); 37 | 38 | var spyPreLayout = sinon.spy(); 39 | app.on( 'preLayout', spyPreLayout ); 40 | 41 | var spyOnLayout = sinon.spy(); 42 | app.on( 'onLayout', spyOnLayout ); 43 | 44 | var spyPostLayout = sinon.spy(); 45 | app.on( 'postLayout', spyPostLayout ); 46 | 47 | var spyPostCompile = sinon.spy(); 48 | app.on( 'postCompile', spyPostCompile ); 49 | 50 | var spyPostRender = sinon.spy(); 51 | app.on( 'postRender', spyPostRender ); 52 | 53 | var spyOnMerge = sinon.spy(); 54 | app.on( 'onMerge', spyOnMerge ); 55 | 56 | app.build( 'default', function ( err ) { 57 | expect( err ).to.not.exist; 58 | 59 | //expect( spyOnLoad ).to.have.been.calledOnce; 60 | //expect( spyOnStream ).to.have.been.calledOnce 61 | //expect( spyOnLayout).to.have.been.calledOnce; 62 | //expect( spyPostLayout).to.have.been.calledOnce; 63 | //expect( spyOnMerge).to.have.been.calledOnce; 64 | 65 | expect( spyPreRender ).to.have.been.calledOnce; 66 | //expect( spyPreRender).to.have.been.calledAfter(spyOnStream); 67 | 68 | expect( spyPreCompile ).to.have.been.calledOnce; 69 | expect( spyPreCompile ).to.have.been.calledAfter( spyPreRender ); 70 | 71 | expect( spyPreLayout ).to.have.been.calledOnce; 72 | expect( spyPreLayout ).to.have.been.calledAfter( spyPreCompile ); 73 | 74 | expect( spyPostCompile ).to.have.been.calledOnce; 75 | expect( spyPostCompile ).to.have.been.calledAfter( spyPreLayout ); 76 | 77 | expect( spyPostRender ).to.have.been.calledOnce; 78 | expect( spyPostRender ).to.have.been.calledAfter( spyPostCompile ); 79 | 80 | done(); 81 | } ); 82 | } ); 83 | } ); 84 | -------------------------------------------------------------------------------- /recipes/middleware/run.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var app = require( './index' ); 3 | 4 | app.build( ['default'], function ( err ) { 5 | if ( err ) { 6 | console.error( 'ERROR: ', err ); 7 | } 8 | } ); 9 | -------------------------------------------------------------------------------- /recipes/permalinks-copy-images/README.md: -------------------------------------------------------------------------------- 1 | ## permalinks-copy-images 2 | 3 | This recipe follows a quite useful - though uncommon - pattern how to store content on GitHub and then use it to create static pages: 4 | 5 | Let's assume you have the following structure on GitHub: 6 | 7 | ```bash 8 | |── content 9 | |── article-1 10 | |── images 11 | | screenshot.png 12 | | another-image.png 13 | | README.md 14 | |── article-2 15 | |── images 16 | | screenshot.png 17 | | another-image.png 18 | | README.md 19 | ``` 20 | 21 | This pattern has some benefits: 22 | - You can send out a link to just the folder and the README.md will always be shown as the default content 23 | - You can reference the images relatively and they will be shown always be shown correctly 24 | - When using hundreds of articles using assembly, you do not run into the risk that you mix-up image names 25 | - The images are always related to its articles, therefore it's easy to move around content 26 | 27 | 28 | Using now `assemble-permalinks` in combination with a `postWrite` middleware copies all files to the generated permalink-folder: 29 | 30 | ```bash 31 | |── articles 32 | |── article-1-permalink 33 | |── images 34 | | screenshot.png 35 | | another-image.png 36 | | index.html 37 | |── article-2-permalink 38 | |── images 39 | | screenshot.png 40 | | another-image.png 41 | | index.html 42 | ``` 43 | -------------------------------------------------------------------------------- /recipes/permalinks-copy-images/content/articles/article-1/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Article 1 3 | category: articles 4 | --- 5 | {{title}} 6 | -------------------------------------------------------------------------------- /recipes/permalinks-copy-images/content/articles/article-1/images/article-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/assemble/assemble-workshop/36d1a041915c773d87c9a412af2b5ed94f1d3aa6/recipes/permalinks-copy-images/content/articles/article-1/images/article-1.png -------------------------------------------------------------------------------- /recipes/permalinks-copy-images/content/articles/article-1/images/dot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/assemble/assemble-workshop/36d1a041915c773d87c9a412af2b5ed94f1d3aa6/recipes/permalinks-copy-images/content/articles/article-1/images/dot.png -------------------------------------------------------------------------------- /recipes/permalinks-copy-images/content/articles/article-2/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Article 2 3 | category: articles 4 | --- 5 | {{title}} 6 | -------------------------------------------------------------------------------- /recipes/permalinks-copy-images/content/articles/article-2/images/article-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/assemble/assemble-workshop/36d1a041915c773d87c9a412af2b5ed94f1d3aa6/recipes/permalinks-copy-images/content/articles/article-2/images/article-2.png -------------------------------------------------------------------------------- /recipes/permalinks-copy-images/content/articles/article-2/images/dot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/assemble/assemble-workshop/36d1a041915c773d87c9a412af2b5ed94f1d3aa6/recipes/permalinks-copy-images/content/articles/article-2/images/dot.png -------------------------------------------------------------------------------- /recipes/permalinks-copy-images/content/posts/2016-01-01-post-1/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Post 1 3 | postData: 2016-01-01 4 | category: posts 5 | --- 6 | {{title}} 7 | -------------------------------------------------------------------------------- /recipes/permalinks-copy-images/content/posts/2016-01-01-post-1/images/dot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/assemble/assemble-workshop/36d1a041915c773d87c9a412af2b5ed94f1d3aa6/recipes/permalinks-copy-images/content/posts/2016-01-01-post-1/images/dot.png -------------------------------------------------------------------------------- /recipes/permalinks-copy-images/content/posts/2016-01-01-post-1/images/post-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/assemble/assemble-workshop/36d1a041915c773d87c9a412af2b5ed94f1d3aa6/recipes/permalinks-copy-images/content/posts/2016-01-01-post-1/images/post-1.png -------------------------------------------------------------------------------- /recipes/permalinks-copy-images/content/posts/2016-01-02-post-2/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Post 2 3 | postData: 2016-01-02 4 | category: posts 5 | --- 6 | {{title}} 7 | -------------------------------------------------------------------------------- /recipes/permalinks-copy-images/content/posts/2016-01-02-post-2/images/dot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/assemble/assemble-workshop/36d1a041915c773d87c9a412af2b5ed94f1d3aa6/recipes/permalinks-copy-images/content/posts/2016-01-02-post-2/images/dot.png -------------------------------------------------------------------------------- /recipes/permalinks-copy-images/content/posts/2016-01-02-post-2/images/post-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/assemble/assemble-workshop/36d1a041915c773d87c9a412af2b5ed94f1d3aa6/recipes/permalinks-copy-images/content/posts/2016-01-02-post-2/images/post-2.png -------------------------------------------------------------------------------- /recipes/permalinks-copy-images/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var assemble = require( 'assemble' ); 3 | var path = require( 'path' ); 4 | var fs = require( 'fs-extra' ); 5 | var permalinks = require( 'assemble-permalinks' ); 6 | var slugify = require( 'slug' ); 7 | 8 | var paths = { 9 | templates: path.join( __dirname, './templates/layouts/**/*.hbs' ), 10 | articleDir: path.join( __dirname, './content/**/*.{md,hbs}' ), 11 | buildDir: path.join( __dirname, './.build' ) 12 | }; 13 | 14 | var app = assemble(); 15 | 16 | app.task( 'init', function ( cb ) { 17 | app.layouts( path.templates ); 18 | cb(); 19 | } ); 20 | 21 | app.create( 'articles' ) 22 | .use( permalinks( path.join( paths.buildDir, 'whatever/:category/:getSlug()/index.html' ), { 23 | getSlug: function () { 24 | if ( this.slug ) { 25 | return slugify( this.slug, {lower: true} ); 26 | } else { 27 | return slugify( this.title, {lower: true} ); 28 | } 29 | } 30 | } ) ); 31 | 32 | app.articles( paths.articleDir ); 33 | 34 | app.postWrite( /\.html/, function ( view, next ) { 35 | var sourcePath = path.dirname( view.key ); 36 | var imagesExist = fs.existsSync( path.join( sourcePath, 'images' ) ); 37 | 38 | if ( imagesExist ) { 39 | var destPath = path.dirname( view.data.permalink ); 40 | return fs.copy( path.join( sourcePath, 'images' ), path.join( destPath, 'images' ), function ( err ) { 41 | if ( err ) { 42 | console.error( err ); 43 | return next( err ); 44 | } 45 | return next(); 46 | } ); 47 | } else { 48 | return next(); 49 | } 50 | } ); 51 | 52 | app.task( 'articles', function () { 53 | return app.toStream( 'articles' ) 54 | .pipe( app.renderFile() ) 55 | .on( 'error', console.error ) 56 | .pipe( app.articles.permalink() ) 57 | .pipe( app.dest( paths.buildDir ) ); 58 | } ); 59 | 60 | app.task( 'default', ['init', 'articles'] ); 61 | 62 | module.exports = app; 63 | -------------------------------------------------------------------------------- /recipes/permalinks-copy-images/index.spec.js: -------------------------------------------------------------------------------- 1 | /*eslint no-unused-expressions:0*/ 2 | 'use strict'; 3 | var chai = require( 'chai' ); 4 | var expect = chai.expect; 5 | var path = require( 'path' ); 6 | var chaiFiles = require( 'chai-files' ); 7 | var utils = require( './../lib/test-utils' ); 8 | 9 | chai.use( chaiFiles ); 10 | var file = chaiFiles.file; 11 | var app = require( './index' ); 12 | 13 | describe( 'permalinks-folder-structure', function () { 14 | 15 | var delPath = path.join( __dirname, './.build' ); 16 | beforeEach( function ( cb ) { 17 | utils.clean( delPath, cb ); 18 | } ); 19 | afterEach( function ( cb ) { 20 | utils.clean( delPath, cb ); 21 | } ); 22 | 23 | it( 'should create the appropriate output', function ( done ) { 24 | app.build( 'default', function ( err ) { 25 | 26 | if ( err ) { console.error( err );} 27 | 28 | expect( file( path.join( __dirname, './.build/whatever/articles/article-1/index.html' ) ) ).to.exist; 29 | expect( file( path.join( __dirname, './.build/whatever/articles/article-1/images/article-1.png' ) ) ).to.exist; 30 | expect( file( path.join( __dirname, './.build/whatever/articles/article-1/images/dot.png' ) ) ).to.exist; 31 | 32 | expect( file( path.join( __dirname, './.build/whatever/articles/article-2/index.html' ) ) ).to.exist; 33 | expect( file( path.join( __dirname, './.build/whatever/articles/article-2/images/article-2.png' ) ) ).to.exist; 34 | expect( file( path.join( __dirname, './.build/whatever/articles/article-2/images/dot.png' ) ) ).to.exist; 35 | 36 | expect( file( path.join( __dirname, './.build/whatever/posts/post-1/index.html' ) ) ).to.exist; 37 | expect( file( path.join( __dirname, './.build/whatever/posts/post-1/images/post-1.png' ) ) ).to.exist; 38 | expect( file( path.join( __dirname, './.build/whatever/posts/post-1/images/dot.png' ) ) ).to.exist; 39 | 40 | expect( file( path.join( __dirname, './.build/whatever/posts/post-2/index.html' ) ) ).to.exist; 41 | expect( file( path.join( __dirname, './.build/whatever/posts/post-2/images/post-2.png' ) ) ).to.exist; 42 | expect( file( path.join( __dirname, './.build/whatever/posts/post-2/images/dot.png' ) ) ).to.exist; 43 | 44 | done(); 45 | } ); 46 | } ); 47 | 48 | } ); 49 | -------------------------------------------------------------------------------- /recipes/permalinks-copy-images/run.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var app = require( './index' ); 3 | 4 | app.build( ['default'], function ( err ) { 5 | if ( err ) { console.error( 'ERROR: ', err ); } 6 | } ); 7 | -------------------------------------------------------------------------------- /recipes/permalinks-copy-images/templates/layouts/index.hbs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/assemble/assemble-workshop/36d1a041915c773d87c9a412af2b5ed94f1d3aa6/recipes/permalinks-copy-images/templates/layouts/index.hbs -------------------------------------------------------------------------------- /recipes/permalinks-folder-per-file-filebase/README.md: -------------------------------------------------------------------------------- 1 | ## Permalinks: folder per file 2 2 | 3 | This recipe solves an issue described here: https://github.com/assemble/assemble-permalinks/issues/7 4 | -------------------------------------------------------------------------------- /recipes/permalinks-folder-per-file-filebase/assemblefile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var assemble = require( 'assemble' ); 3 | var path = require( 'path' ); 4 | var plugin = require( './src/plugins' ); 5 | 6 | var paths = { 7 | buildDir: path.join( __dirname, './.build/articles' ), 8 | srcDir: path.join( __dirname, './content/articles/**/*.{md,hbs}' ) 9 | }; 10 | 11 | var app = assemble(); 12 | 13 | app.create( 'articles' ) 14 | .use( plugin.permalinks( path.join( paths.buildDir, ':name/index.html' ) ) ); 15 | 16 | app.articles( paths.srcDir ); 17 | 18 | app.task( 'articles', function () { 19 | return app.toStream( 'articles' ) 20 | .pipe( app.renderFile() ) 21 | .on( 'error', console.error ) 22 | .pipe( app.articles.permalink() ) 23 | .on( 'error', console.error ) 24 | .pipe( app.dest( function ( file ) { 25 | file.base = paths.buildDir; 26 | return paths.buildDir; 27 | } ) ) 28 | .on( 'error', console.error ); 29 | } ); 30 | 31 | app.task( 'default', [ 32 | 'articles' 33 | ] ); 34 | 35 | module.exports = app; 36 | -------------------------------------------------------------------------------- /recipes/permalinks-folder-per-file-filebase/content/articles/bar.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: bar 3 | --- 4 | {{title}} 5 | -------------------------------------------------------------------------------- /recipes/permalinks-folder-per-file-filebase/content/articles/baz.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: baz 3 | --- 4 | {{title}} 5 | -------------------------------------------------------------------------------- /recipes/permalinks-folder-per-file-filebase/content/articles/foo.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: foo 3 | --- 4 | {{title}} 5 | -------------------------------------------------------------------------------- /recipes/permalinks-folder-per-file-filebase/index.spec.js: -------------------------------------------------------------------------------- 1 | /*eslint no-unused-expressions:0*/ 2 | 'use strict'; 3 | var chai = require( 'chai' ); 4 | var expect = chai.expect; 5 | var path = require( 'path' ); 6 | var chaiFiles = require( 'chai-files' ); 7 | var utils = require( './../lib/test-utils' ); 8 | 9 | chai.use( chaiFiles ); 10 | var file = chaiFiles.file; 11 | var app = require( './assemblefile' ); 12 | 13 | describe( 'permalinks-folder-per-file-filebase', function () { 14 | 15 | var delPath = path.join( __dirname, './.build' ); 16 | beforeEach( function ( cb ) { 17 | utils.clean( delPath, cb ); 18 | } ); 19 | afterEach( function ( cb ) { 20 | utils.clean( delPath, cb ); 21 | } ); 22 | 23 | it( 'should create a folder (+ index.html) per file', function ( done ) { 24 | app.build( ['default'], function ( err ) { 25 | 26 | if ( err ) { console.error( err );} 27 | 28 | expect( file( path.join( __dirname, './.build/articles/foo/index.html' ) ) ).to.exist; 29 | expect( file( path.join( __dirname, './.build/articles/bar/index.html' ) ) ).to.exist; 30 | expect( file( path.join( __dirname, './.build/articles/baz/index.html' ) ) ).to.exist; 31 | 32 | done(); 33 | } ); 34 | } ); 35 | 36 | } ); 37 | -------------------------------------------------------------------------------- /recipes/permalinks-folder-per-file-filebase/run.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var app = require( './assemblefile' ); 3 | 4 | app.build( ['default'], function ( err ) { 5 | if ( err ) { 6 | console.error( 'ERROR: ', err ); 7 | } 8 | } ); 9 | -------------------------------------------------------------------------------- /recipes/permalinks-folder-per-file-filebase/src/plugins/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var plugins = module.exports = require( 'export-files' )( __dirname ); 4 | plugins.permalinks = require( 'assemble-permalinks' ); 5 | -------------------------------------------------------------------------------- /recipes/permalinks-folder-per-file/README.md: -------------------------------------------------------------------------------- 1 | ## Permalinks - Folder per file 2 | 3 | Recipe to showcase how to use `assemble-permalinks` to create a folder per file (based on the underlying folder-structure): 4 | 5 | ### Source 6 | 7 | ``` 8 | |── content 9 | |── folder-1 10 | |── folder-1-1 11 | | c.md 12 | | d.md 13 | | a.md 14 | |── folder-2 15 | | b.md 16 | | y.md 17 | | z.md 18 | ``` 19 | 20 | ### Result 21 | 22 | ```js 23 | |── content 24 | |── folder-1 25 | |── a 26 | | index.html 27 | |── folder-1-1 28 | |── c 29 | | index.html 30 | |── d 31 | | index.html 32 | |── folder-2 33 | |── b 34 | | index.html 35 | |── y 36 | | index.html 37 | |── z 38 | | index.html 39 | 40 | ``` 41 | 42 | ### Code 43 | 44 | ```js 45 | 46 | 'use strict'; 47 | var assemble = require( 'assemble' ); 48 | var path = require( 'path' ); 49 | var permalinks = require( 'assemble-permalinks' ); 50 | 51 | var paths = { 52 | buildDir: path.join( __dirname, './.build' ), 53 | srcDir: path.join( __dirname, './content/**/*.{md,hbs}' ) 54 | }; 55 | 56 | var app = assemble(); 57 | 58 | app.create( 'articles' ) 59 | .use( permalinks( path.join( paths.buildDir, ':getQualifiedName()/index.html' ), { 60 | getQualifiedName: function () { 61 | var relPath = path.relative( this.base, this.dirname ); 62 | return path.join( relPath, this.name ); 63 | } 64 | } ) ); 65 | 66 | app.articles( paths.srcDir ); 67 | 68 | app.task( 'articles', function () { 69 | return app.toStream( 'articles' ) 70 | .pipe( app.renderFile() ) 71 | .on( 'error', console.error ) 72 | .pipe( app.articles.permalink() ) 73 | .on( 'error', console.error ) 74 | .pipe( app.dest( paths.buildDir ) ) 75 | .on( 'error', console.error ); 76 | } ); 77 | 78 | app.task( 'default', [ 79 | 'articles' 80 | ] ); 81 | 82 | module.exports = app; 83 | 84 | ``` 85 | 86 | -------------------------------------------------------------------------------- /recipes/permalinks-folder-per-file/content/folder-1/a.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: a (folder-1) 3 | --- 4 | {{title}} 5 | -------------------------------------------------------------------------------- /recipes/permalinks-folder-per-file/content/folder-1/folder-1-1/c.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: c (folder-1-1) 3 | --- 4 | {{title}} 5 | -------------------------------------------------------------------------------- /recipes/permalinks-folder-per-file/content/folder-1/folder-1-1/d.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: d (folder-1-1) 3 | --- 4 | {{title}} 5 | -------------------------------------------------------------------------------- /recipes/permalinks-folder-per-file/content/folder-2/b.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: b (folder-2) 3 | --- 4 | {{title}} 5 | -------------------------------------------------------------------------------- /recipes/permalinks-folder-per-file/content/y.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: y 3 | --- 4 | {{title}} 5 | -------------------------------------------------------------------------------- /recipes/permalinks-folder-per-file/content/z.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: z 3 | --- 4 | {{title}} 5 | -------------------------------------------------------------------------------- /recipes/permalinks-folder-per-file/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var assemble = require( 'assemble' ); 3 | var path = require( 'path' ); 4 | var permalinks = require( 'assemble-permalinks' ); 5 | 6 | var paths = { 7 | buildDir: path.join( __dirname, './.build' ), 8 | srcDir: path.join( __dirname, './content/**/*.{md,hbs}' ) 9 | }; 10 | 11 | var app = assemble(); 12 | 13 | app.create( 'articles' ) 14 | .use( permalinks( path.join( paths.buildDir, ':getQualifiedName()/index.html' ), { 15 | getQualifiedName: function () { 16 | var relPath = path.relative( this.base, this.dirname ); 17 | return path.join( relPath, this.name ); 18 | } 19 | } ) ); 20 | 21 | app.articles( paths.srcDir ); 22 | 23 | app.task( 'articles', function () { 24 | return app.toStream( 'articles' ) 25 | .pipe( app.renderFile() ) 26 | .on( 'error', console.error ) 27 | .pipe( app.articles.permalink() ) 28 | .on( 'error', console.error ) 29 | .pipe( app.dest( paths.buildDir ) ) 30 | .on( 'error', console.error ); 31 | } ); 32 | 33 | app.task( 'default', [ 34 | 'articles' 35 | ] ); 36 | 37 | module.exports = app; 38 | -------------------------------------------------------------------------------- /recipes/permalinks-folder-per-file/index.spec.js: -------------------------------------------------------------------------------- 1 | /*eslint no-unused-expressions:0*/ 2 | 'use strict'; 3 | var chai = require( 'chai' ); 4 | var expect = chai.expect; 5 | var path = require( 'path' ); 6 | var chaiFiles = require( 'chai-files' ); 7 | var utils = require( './../lib/test-utils' ); 8 | 9 | chai.use( chaiFiles ); 10 | var file = chaiFiles.file; 11 | var app = require( './index' ); 12 | 13 | describe( 'permalinks-folder-per-file', function () { 14 | 15 | var delPath = path.join( __dirname, './.build' ); 16 | beforeEach( function ( cb ) { 17 | utils.clean( delPath, cb ); 18 | } ); 19 | afterEach( function ( cb ) { 20 | utils.clean( delPath, cb ); 21 | } ); 22 | 23 | it( 'should create a folder per file', function ( done ) { 24 | app.build( ['default'], function ( err ) { 25 | 26 | if ( err ) { console.error( err );} 27 | 28 | expect( file( path.join( __dirname, './.build/y/index.html' ) ) ).to.exist; 29 | expect( file( path.join( __dirname, './.build/z/index.html' ) ) ).to.exist; 30 | 31 | expect( file( path.join( __dirname, './.build/folder-1/a/index.html' ) ) ).to.exist; 32 | expect( file( path.join( __dirname, './.build/folder-1/folder-1-1/c/index.html' ) ) ).to.exist; 33 | expect( file( path.join( __dirname, './.build/folder-1/folder-1-1/d/index.html' ) ) ).to.exist; 34 | 35 | expect( file( path.join( __dirname, './.build/folder-2/b/index.html' ) ) ).to.exist; 36 | 37 | done(); 38 | } ); 39 | } ); 40 | 41 | } ); 42 | -------------------------------------------------------------------------------- /recipes/permalinks-folder-per-file/run.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var app = require( './index' ); 3 | 4 | app.build( ['default'], function ( err ) { 5 | if ( err ) { 6 | console.error( 'ERROR: ', err ); 7 | } 8 | } ); 9 | -------------------------------------------------------------------------------- /recipes/permalinks/README.md: -------------------------------------------------------------------------------- 1 | ## Working with permalinks 2 | 3 | -------------------------------------------------------------------------------- /recipes/permalinks/content/articles/article-1/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Article 1 3 | category: articles 4 | slug: article-1-updated-slug 5 | --- 6 | {{title}} 7 | -------------------------------------------------------------------------------- /recipes/permalinks/content/articles/article-2/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Article 2 3 | category: articles 4 | --- 5 | {{title}} 6 | -------------------------------------------------------------------------------- /recipes/permalinks/content/posts/post-1/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Post 1 3 | category: posts 4 | slug: post-1 5 | --- 6 | Post 1 7 | -------------------------------------------------------------------------------- /recipes/permalinks/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var assemble = require( 'assemble' ); 3 | var path = require( 'path' ); 4 | var utils = require( './../lib/utils' ); 5 | var permalinks = require( 'assemble-permalinks' ); 6 | var del = require( 'del' ); 7 | var slugify = require( 'slug' ); 8 | 9 | var paths = { 10 | buildDir: path.join( __dirname, './.build' ), 11 | srcDir: path.join( __dirname, './content/**/*.{md,hbs}' ), 12 | templates: path.join( __dirname, './templates/layouts/**/*.hbs' ) 13 | }; 14 | 15 | var app = assemble(); 16 | 17 | app.create( 'articles' /*, {layout: 'body'}*/ ) 18 | .use( permalinks( path.join( paths.buildDir, 'whatever/:category/:getSlug()/index.html' ), { 19 | getSlug: function () { 20 | if ( this.slug ) { 21 | return slugify( this.slug, {lower: true} ); 22 | } else { 23 | return slugify( this.title, {lower: true} ); 24 | } 25 | } 26 | } ) ); 27 | 28 | app.articles( paths.srcDir ); 29 | 30 | app.option( 'renameKey', function ( key /*, view */ ) { 31 | key = path.relative( path.join( __dirname, './content/' ), key ); 32 | return utils.stripExtension( key, path.extname( key ) ); 33 | } ); 34 | 35 | app.task( 'load-templates', function ( cb ) { 36 | app.layouts( paths.templates ); 37 | cb(); 38 | } ); 39 | 40 | app.task( 'articles', function () { 41 | return app.toStream( 'articles' ) 42 | .pipe( app.renderFile() ) 43 | .on( 'error', console.error ) 44 | .pipe( app.articles.permalink() ) 45 | .pipe( app.dest( paths.buildDir ) ); 46 | } ); 47 | 48 | /** 49 | * Clean the output director. 50 | */ 51 | app.task( 'clean', function ( cb ) { 52 | del( paths.buildDir ).then( function () { 53 | cb(); 54 | } ); 55 | } ); 56 | 57 | /** 58 | * Main task 59 | */ 60 | app.task( 'default', [ 61 | 'clean', 62 | 'load-templates', 63 | 'articles' 64 | ] ); 65 | 66 | module.exports = app; 67 | -------------------------------------------------------------------------------- /recipes/permalinks/index.spec.js: -------------------------------------------------------------------------------- 1 | /*eslint no-unused-expressions:0*/ 2 | 'use strict'; 3 | var chai = require( 'chai' ); 4 | var expect = chai.expect; 5 | var path = require( 'path' ); 6 | var chaiFiles = require( 'chai-files' ); 7 | var utils = require( './../lib/test-utils' ); 8 | 9 | chai.use( chaiFiles ); 10 | var file = chaiFiles.file; 11 | var app = require( './index' ); 12 | 13 | describe( 'permalinks', function () { 14 | 15 | var delPath = path.join( __dirname, './.build' ); 16 | beforeEach( function ( cb ) { 17 | utils.clean( delPath, cb ); 18 | } ); 19 | afterEach( function ( cb ) { 20 | utils.clean( delPath, cb ); 21 | } ); 22 | 23 | it( 'should create the appropriate output', function ( done ) { 24 | app.build( 'default', function ( err ) { 25 | if ( err ) { console.error( err ); } 26 | expect( file( path.join( __dirname, './.build/whatever/articles/article-1-updated-slug/index.html' ) ) ).to.exist; 27 | expect( file( path.join( __dirname, './.build/whatever/articles/article-2/index.html' ) ) ).to.exist; 28 | expect( file( path.join( __dirname, './.build/whatever/posts/post-1/index.html' ) ) ).to.exist; 29 | return done(); 30 | } ); 31 | } ); 32 | 33 | } ); 34 | -------------------------------------------------------------------------------- /recipes/permalinks/run.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var app = require( './index' ); 3 | 4 | app.build( ['default'], function ( err ) { 5 | if ( err ) { 6 | console.error( 'ERROR: ', err ); 7 | } 8 | } ); 9 | -------------------------------------------------------------------------------- /recipes/permalinks/templates/layouts/body.hbs: -------------------------------------------------------------------------------- 1 | {% body %} 2 | -------------------------------------------------------------------------------- /recipes/visual-studio-integration/assemblefile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var assemble = require( 'assemble' ); 4 | var path = require( 'path' ); 5 | var less = require( 'gulp-less' ); 6 | var ext = require( 'gulp-extname' ); 7 | var watch = require( 'base-watch' ); 8 | var browserSync = require( 'browser-sync' ).create(); 9 | var app = assemble(); 10 | 11 | app.use( watch() ); 12 | app.option( 'layout', 'default' ); 13 | app.data( 'src/data/**/*.json' ); 14 | 15 | //use some middleware to set the default layout if not explicitly defined in the current document: 16 | app.preLayout( /./, function ( view, next ) { 17 | // if the layout is not defined, use the default one ... 18 | if ( !view.layout && app.options.layout ) { 19 | view.layout = app.options.layout; 20 | } 21 | next(); 22 | } ); 23 | 24 | app.task( 'init', function ( cb ) { 25 | //setup assemble 26 | 27 | app.helpers( 'node_modules/handlebars-helpers/lib' ); 28 | 29 | app.helper( 'isActive', function ( title ) { 30 | //custom helper to mark 'current page' as active in bootstrap menu 31 | if ( this.context.title === title ) { 32 | return 'class="active"'; 33 | } else { 34 | return ''; 35 | } 36 | } ); 37 | 38 | app.layouts( path.join( __dirname, 'src/layouts/**/*.hbs' ) ); 39 | cb(); 40 | } ); 41 | 42 | app.task( 'default', ['pages', 'assets', 'serve'], function () { 43 | // placeholder to recompile entire site, start watching and spin up browsersync... 44 | } ); 45 | 46 | app.task( 'rebuild', ['pages', 'assets'], function () { 47 | //placeholder to rebuild entire site 48 | } ); 49 | 50 | app.task( 'pages', ['init'], function () { 51 | return app.src( 'src/pages/**/*.hbs', {layout: 'default'} ) 52 | .pipe( app.renderFile() ) 53 | .pipe( ext()) 54 | .pipe( app.dest( 'wwwroot' ) ) 55 | .pipe( browserSync.stream() ); 56 | } ); 57 | 58 | app.task( 'assets', ['js', 'css', 'bower'], function () { 59 | return app.src( 'src/assets/**/*.{css, png, jpg, js}' ) 60 | .pipe( app.dest( 'wwwroot/assets/' ) ); 61 | } ); 62 | 63 | app.task( 'css', function () { 64 | return app.src( 'src/assets/**/*.less' ) 65 | .pipe( less() ) 66 | .pipe( ext()) 67 | .pipe( app.dest( 'wwwroot/assets/' ) ) 68 | .pipe( browserSync.stream() ); 69 | } ); 70 | 71 | app.task( 'js', function () { 72 | return app.src( 'src/assets/**/*.js' ) 73 | .pipe( app.dest( 'wwwroot/assets/' ) ); 74 | } ); 75 | 76 | app.task( 'bower', function () { 77 | //copy the files we need from their bower packages 78 | app.src( ['bower_components/jquery/dist/jquery.min.js'] ) 79 | .pipe( app.dest( 'wwwroot/assets/js' ) ); 80 | 81 | return app.src( ['bower_components/bootstrap/dist/**/*.{min.js,min.css,ttf,svg,woff,eot,woff2}'] ) 82 | .pipe( app.dest( 'wwwroot/assets/' ) ); 83 | } ); 84 | 85 | app.task( 'serve', ['watch'], function () { 86 | browserSync.init( { 87 | port: 8080, 88 | startPath: 'index.html', 89 | server: { 90 | baseDir: './wwwroot' 91 | } 92 | } ); 93 | } ); 94 | 95 | app.task( 'watch', function ( cb ) { 96 | //watch for changes and run tasks for those file types. 97 | app.watch( 'src/**/*.hbs', ['pages'] ); 98 | app.watch( 'src/data/**/*.json', ['pages'] ); 99 | app.watch( 'src/assets/**/*.less', ['css'] ); 100 | app.watch( 'src/assets/**/*.js', ['js'] ); 101 | cb(); 102 | } ); 103 | 104 | app.task( 'publish', function ( cb ) { 105 | //here is where you could place code to publish the site 106 | console.log( 'deploying..' ); 107 | cb(); 108 | } ); 109 | 110 | module.exports = app; 111 | -------------------------------------------------------------------------------- /recipes/visual-studio-integration/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vs-integration-recipes", 3 | "description": "", 4 | "main": "index.js", 5 | "authors": [ 6 | "ITLackey" 7 | ], 8 | "license": "ISC", 9 | "homepage": "", 10 | "private": true, 11 | "ignore": [ 12 | "**/.*", 13 | "node_modules", 14 | "bower_components", 15 | "test", 16 | "tests" 17 | ], 18 | "dependencies": { 19 | "bootstrap": "^3.3.6" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /recipes/visual-studio-integration/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vs-integration-recipe", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "dependencies": { }, 7 | "devDependencies": { 8 | "assemble": "^0.12.0", 9 | "assemble-handlebars": "^0.3.0", 10 | "handlebars-helpers": "^0.6.1", 11 | "base-watch": "^0.1.3", 12 | "browser-sync": "^2.13.0", 13 | "gulp": "^3.9.1", 14 | "gulp-extname": "^0.2.2", 15 | "gulp-less": "^3.1.0" 16 | }, 17 | "author": "ITLackey", 18 | "license": "ISC", 19 | "scripts": { 20 | "build": "assemble pages", 21 | "rebuild": "assemble rebuild", 22 | "start": "assemble", 23 | "deploy": "assemble publish" 24 | }, 25 | "-vs-binding":{"BeforeBuild":["build"],"Clean":["rebuild","build"]} 26 | } 27 | -------------------------------------------------------------------------------- /recipes/visual-studio-integration/readme.md: -------------------------------------------------------------------------------- 1 | # Visual Studio Integration 2 | 3 | > This recipe describes how to use assemble within Visual Studio and builds upon the [browser-sync recipe](https://github.com/assemble/assemble-recipes/tree/master/recipes/browser-sync). 4 | 5 | ## Purpose of this recipe 6 | - The primary purpose is to demonstrate using assemble with the Visual Studio IDE 7 | 8 | ### Additional examples 9 | Additionally these topics are also demonstrated in this recipe 10 | 11 | - Convert some .less files to a single style sheet (.css file). 12 | - Convert some .hbs files to HTML output, using styles in the generated CSS file. 13 | - Serve the files in the local browser automatically 14 | - Using site metadata 15 | - Using a default layout file 16 | - Load handlebars-helpers 17 | - Using bower packages 18 | - Using a Bootstrap theme in the layout 19 | - Defining a custom helper 20 | - Create some watchers on 21 | - all .less files (`./src/assets/css` folder) 22 | - all .js files (`./src/assets/js` folder) 23 | - all content files (`./src/pages` and `./src/layouts` folders) 24 | - all data files (`./src/data` folder) 25 | - In case any watcher is triggered, update the corresponding files. 26 | 27 | ## Overview 28 | 29 | This recipe describes how you can leverage assemble within Visual Studio. Included 30 | in this template is an example of a simple site that is using some bower packages, 31 | a bootstrap example theme and some gulp plug-ins within assemble. 32 | 33 | This recipe is not meant to be an example of best practices and it should be 34 | used only as reference when starting an assemble project. 35 | 36 | ## Visual Studio Extensions 37 | 38 | To begin the following visual studio extensions must be installed. 39 | 40 | - [Task Runner Explorer](https://visualstudiogallery.msdn.microsoft.com/8e1b4368-4afb-467a-bc13-9650572db708) 41 | - [NPM Task Runner](https://visualstudiogallery.msdn.microsoft.com/8f2f2cbc-4da5-43ba-9de2-c9d08ade4941) 42 | 43 | 44 | ## Visual Studio Fix 45 | 46 | By default Visual Studio uses node 0.10.x for its Task Runner Explorer. 47 | In order to have the task runner use a newer version of node the options 48 | for the External Web Tools must be changed. Specifically the order of the 49 | paths in which visual studio looks for web tools must be modified. This 50 | article describes the issue and explains the solution in detail. 51 | 52 | [Customize external web tools in visual studio 2015](https://blogs.msdn.microsoft.com/webdev/2015/03/19/customize-external-web-tools-in-visual-studio-2015/) 53 | 54 | 55 | ## NPM Tasks Configuration 56 | 57 | By configuring the scripts section the of the package.json in the project 58 | the Task Runner Explorer will display these tasks and allow the to be 59 | run manually using the context menu. These script definitions are simply 60 | examples and the scripts can be defined differently to meet projects 61 | requirements. 62 | 63 | ``` json 64 | "scripts": { 65 | "build": "assemble pages", 66 | "rebuild": "assemble rebuild", 67 | "start": "assemble", 68 | "deploy": "assemble publish" 69 | } 70 | ``` 71 | 72 | ## Visual Studio Event Bindings 73 | 74 | Using the context menu in the Task Runner Explorer for the 75 | scripts defined in your package.json file 76 | you can bind assemble commands to Visual Studio events such as 77 | Project Open, Before Build, After Build and Clean. Doing so 78 | adds an additional section to the package.json file to hold 79 | the event bindings. It looks similar to the following snippet. 80 | 81 | ``` json 82 | "-vs-binding":{"BeforeBuild":["build"]} 83 | ``` 84 | 85 | 86 | 87 | ## References 88 | 89 | Information was used from the following resources in this recipe 90 | 91 | * [Task Runner Explorer](https://visualstudiogallery.msdn.microsoft.com/8e1b4368-4afb-467a-bc13-9650572db708) 92 | * [NPM Task Runner](https://visualstudiogallery.msdn.microsoft.com/8f2f2cbc-4da5-43ba-9de2-c9d08ade4941) 93 | * [Fix Web Tools Path](https://blogs.msdn.microsoft.com/webdev/2015/03/19/customize-external-web-tools-in-visual-studio-2015/) 94 | * [Theme](http://getbootstrap.com/examples/carousel/) 95 | * [About Page](http://bootsnipp.com/snippets/6n1ym) 96 | * [Contact Us](http://bootsnipp.com/snippets/featured/contact-us-page) -------------------------------------------------------------------------------- /recipes/visual-studio-integration/src/assets/css/carousel.css: -------------------------------------------------------------------------------- 1 | /* GLOBAL STYLES 2 | -------------------------------------------------- */ 3 | /* Padding below the footer and lighter body text */ 4 | 5 | body { 6 | padding-bottom: 40px; 7 | color: #5a5a5a; 8 | } 9 | 10 | 11 | /* CUSTOMIZE THE NAVBAR 12 | -------------------------------------------------- */ 13 | 14 | /* Special class on .container surrounding .navbar, used for positioning it into place. */ 15 | .navbar-wrapper { 16 | position: absolute; 17 | top: 0; 18 | right: 0; 19 | left: 0; 20 | z-index: 20; 21 | } 22 | 23 | /* Flip around the padding for proper display in narrow viewports */ 24 | .navbar-wrapper > .container { 25 | padding-right: 0; 26 | padding-left: 0; 27 | } 28 | .navbar-wrapper .navbar { 29 | padding-right: 15px; 30 | padding-left: 15px; 31 | } 32 | .navbar-wrapper .navbar .container { 33 | width: auto; 34 | } 35 | 36 | 37 | /* CUSTOMIZE THE CAROUSEL 38 | -------------------------------------------------- */ 39 | 40 | /* Carousel base class */ 41 | .carousel { 42 | height: 500px; 43 | margin-bottom: 60px; 44 | } 45 | /* Since positioning the image, we need to help out the caption */ 46 | .carousel-caption { 47 | z-index: 10; 48 | } 49 | 50 | /* Declare heights because of positioning of img element */ 51 | .carousel .item { 52 | height: 500px; 53 | background-color: #777; 54 | } 55 | .carousel-inner > .item > img { 56 | position: absolute; 57 | top: 0; 58 | left: 0; 59 | min-width: 100%; 60 | height: 500px; 61 | } 62 | 63 | 64 | /* MARKETING CONTENT 65 | -------------------------------------------------- */ 66 | 67 | /* Center align the text within the three columns below the carousel */ 68 | .marketing .col-lg-4 { 69 | margin-bottom: 20px; 70 | text-align: center; 71 | } 72 | .marketing h2 { 73 | font-weight: normal; 74 | } 75 | .marketing .col-lg-4 p { 76 | margin-right: 10px; 77 | margin-left: 10px; 78 | } 79 | 80 | 81 | /* Featurettes 82 | ------------------------- */ 83 | 84 | .featurette-divider { 85 | margin: 80px 0; /* Space out the Bootstrap
more */ 86 | } 87 | 88 | /* Thin out the marketing headings */ 89 | .featurette-heading { 90 | font-weight: 300; 91 | line-height: 1; 92 | letter-spacing: -1px; 93 | } 94 | 95 | 96 | /* RESPONSIVE CSS 97 | -------------------------------------------------- */ 98 | 99 | @media (min-width: 768px) { 100 | /* Navbar positioning foo */ 101 | .navbar-wrapper { 102 | margin-top: 0; 103 | } 104 | .navbar-wrapper .container { 105 | padding-right: 15px; 106 | padding-left: 15px; 107 | } 108 | .navbar-wrapper .navbar { 109 | padding-right: 0; 110 | padding-left: 0; 111 | } 112 | 113 | /* The navbar becomes detached from the top, so we round the corners */ 114 | .navbar-wrapper .navbar { 115 | border-radius: 4px; 116 | } 117 | 118 | /* Bump up size of carousel content */ 119 | .carousel-caption p { 120 | margin-bottom: 20px; 121 | font-size: 21px; 122 | line-height: 1.4; 123 | } 124 | 125 | .featurette-heading { 126 | font-size: 50px; 127 | } 128 | } 129 | 130 | @media (min-width: 992px) { 131 | .featurette-heading { 132 | margin-top: 120px; 133 | } 134 | } -------------------------------------------------------------------------------- /recipes/visual-studio-integration/src/assets/css/ie10-viewport-bug-workaround.css: -------------------------------------------------------------------------------- 1 |  2 | /*! 3 | * IE10 viewport hack for Surface/desktop Windows 8 bug 4 | * Copyright 2014-2015 Twitter, Inc. 5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 6 | */ 7 | 8 | /* 9 | * See the Getting Started docs for more information: 10 | * http://getbootstrap.com/getting-started/#support-ie10-width 11 | */ 12 | @-webkit-viewport { width: device-width; } 13 | @-moz-viewport { width: device-width; } 14 | @-ms-viewport { width: device-width; } 15 | @-o-viewport { width: device-width; } 16 | @viewport { width: device-width; } 17 | 18 | -------------------------------------------------------------------------------- /recipes/visual-studio-integration/src/assets/css/styles.less: -------------------------------------------------------------------------------- 1 | @import url("http://maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css"); 2 | 3 | .marketing{ 4 | margin-top: 80px; 5 | } 6 | 7 | /*contact*/ 8 | .jumbotron { 9 | background: #358CCE; 10 | color: #FFF; 11 | border-radius: 0px; 12 | } 13 | 14 | .jumbotron-sm { 15 | padding-top: 24px; 16 | padding-bottom: 24px; 17 | } 18 | 19 | .jumbotron small { 20 | color: #FFF; 21 | } 22 | 23 | .h1 small { 24 | font-size: 24px; 25 | } 26 | 27 | 28 | /*About */ 29 | .panel-pricing { 30 | -moz-transition: all .3s ease; 31 | -o-transition: all .3s ease; 32 | -webkit-transition: all .3s ease; 33 | } 34 | .panel-pricing:hover { 35 | box-shadow: 0px 0px 30px rgba(0, 0, 0, 0.2); 36 | } 37 | .panel-pricing .panel-heading { 38 | padding: 20px 10px; 39 | } 40 | .panel-pricing .panel-heading .fa { 41 | margin-top: 10px; 42 | font-size: 58px; 43 | } 44 | .panel-pricing .list-group-item { 45 | color: #777777; 46 | border-bottom: 1px solid rgba(250, 250, 250, 0.5); 47 | } 48 | .panel-pricing .list-group-item:last-child { 49 | border-bottom-right-radius: 0px; 50 | border-bottom-left-radius: 0px; 51 | } 52 | .panel-pricing .list-group-item:first-child { 53 | border-top-right-radius: 0px; 54 | border-top-left-radius: 0px; 55 | } 56 | .panel-pricing .panel-body { 57 | background-color: #f0f0f0; 58 | font-size: 40px; 59 | color: #777777; 60 | padding: 20px; 61 | margin: 0px; 62 | } 63 | -------------------------------------------------------------------------------- /recipes/visual-studio-integration/src/assets/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/assemble/assemble-workshop/36d1a041915c773d87c9a412af2b5ed94f1d3aa6/recipes/visual-studio-integration/src/assets/images/icon.png -------------------------------------------------------------------------------- /recipes/visual-studio-integration/src/assets/js/ie10-viewport-bug-workaround.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | /*! 3 | * IE10 viewport hack for Surface/desktop Windows 8 bug 4 | * Copyright 2014-2015 Twitter, Inc. 5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 6 | */ 7 | 8 | // See the Getting Started docs for more information: 9 | // http://getbootstrap.com/getting-started/#support-ie10-width 10 | 11 | (function () { 12 | 'use strict'; 13 | 14 | if (navigator.userAgent.match(/IEMobile\/10\.0/)) { 15 | var msViewportStyle = document.createElement('style'); 16 | msViewportStyle.appendChild( 17 | document.createTextNode( 18 | '@-ms-viewport{width:auto!important}' 19 | ) 20 | ); 21 | document.querySelector('head').appendChild(msViewportStyle) 22 | } 23 | 24 | })(); 25 | /* eslint-enable */ 26 | -------------------------------------------------------------------------------- /recipes/visual-studio-integration/src/data/site.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Example Site Template", 3 | "author": "ITLackey", 4 | "keywords": "example metadata, assemble", 5 | "description": "This is an example site template", 6 | "email": "example@email.com", 7 | "ga_code": "XXX", 8 | "gse_code": "XXX", 9 | "facebook": "", 10 | "twitter": "", 11 | "googleplus": "" 12 | } -------------------------------------------------------------------------------- /recipes/visual-studio-integration/src/layouts/default.hbs: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | {{title}} - {{site.title}} 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 27 | 28 | 29 | 30 | 31 | 32 | 68 |
69 | 70 | {% body %} 71 | 72 | 73 | 77 |
78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /recipes/visual-studio-integration/src/pages/about.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | title: About 3 | --- 4 | 5 | 6 |
7 |
8 |
9 | 10 | 11 |
12 |
13 |
14 | 15 |

Requirements

16 |
17 | 18 |
    19 |
  • Network
  • 20 |
  • Speed
  • 21 |
  • SIM
  • 22 |
  • Modem
  • 23 |
  • Connection
  • 24 |
  • Sender ID (Branded SMS)
  • 25 |
  • Interaction
  • 26 |
  • Personalize SMS
  • 27 |
  • Scheduler
  • 28 |
  • Fee
  • 29 |
  • Application
  • 30 |
  • Cost of SMS
  • 31 |
  • Load Expiry
  • 32 |
  • UNLITXT Promos
  • 33 |
  • International SMS
  • 34 |
35 | 36 |
37 |
38 | 39 | 40 |
41 |
42 |
43 | 44 |

Busybee PowerBlast

45 |
46 |
    47 |
  • GSM
  • 48 |
  • 15 – 20 SMS per minute
  • 49 |
  • SIM needed
  • 50 |
  • Modem needed
  • 51 |
  • Offline
  • 52 |
  • No
  • 53 |
  • Two-way
  • 54 |
  • Yes
  • 55 |
  • Yes
  • 56 |
  • You pay for the software
  • 57 |
  • With fee
  • 58 |
  • Normal cellphone charges apply (SIM)
  • 59 |
  • Not applicable
  • 60 |
  • Yes (will depend on the SIM)
  • 61 |
  • Yes (will depend on the SIM)
  • 62 |
63 | 64 |
65 |
66 | 67 | 68 |
69 |
70 |
71 | 72 |

Busybee BrandTxT

73 |
74 | 75 |
    76 |
  • SMS Gateway
  • 77 |
  • 1 SMS per second
  • 78 |
  • No need for SIM
  • 79 |
  • No need for Modem
  • 80 |
  • Online
  • 81 |
  • Yes
  • 82 |
  • One-way
  • 83 |
  • Yes
  • 84 |
  • Yes
  • 85 |
  • You pay for the SMS
  • 86 |
  • Free
  • 87 |
  • PHP 1.00 per SMS ($0.025)
  • 88 |
  • Without Expiry
  • 89 |
  • No
  • 90 |
  • Yes
  • 91 |
92 |
93 |
94 | 95 | 96 |
97 |
98 |
99 | -------------------------------------------------------------------------------- /recipes/visual-studio-integration/src/pages/contact.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | title: Contact Us 3 | --- 4 | 5 | 6 |
7 |
8 |
9 |
10 |

11 | Contact us Feel free to contact us 12 |

13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | 28 | 29 |
30 |
31 | 34 |
35 | 36 | 37 | 38 | 39 |
40 |
41 |
42 | 45 | 51 |
52 |
53 |
54 |
55 | 58 | 60 |
61 |
62 |
63 | 66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |  Our office 74 |
75 | Twitter, Inc.
76 | 795 Folsom Ave, Suite 600
77 | San Francisco, CA 94107
78 | 79 | P: 80 | 81 | (123) 456-7890 82 |
83 |
84 | Full Name
85 | first.last@example.com 86 |
87 |
88 |
89 |
90 |
91 | -------------------------------------------------------------------------------- /recipes/visual-studio-integration/src/pages/index.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | title: Home 3 | --- 4 | 6 | 54 | 56 | 57 | 58 |
59 | 60 | 61 |
62 |
63 | Generic placeholder image 64 |

Heading

65 |

Donec sed odio dui. Etiam porta sem malesuada magna mollis euismod. Nullam id dolor id nibh ultricies vehicula ut id elit. Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Praesent commodo cursus magna.

66 |

View details »

67 |
68 |
69 | Generic placeholder image 70 |

Heading

71 |

Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Cras mattis consectetur purus sit amet fermentum. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh.

72 |

View details »

73 |
74 |
75 | Generic placeholder image 76 |

Heading

77 |

Donec sed odio dui. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Vestibulum id ligula porta felis euismod semper. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus.

78 |

View details »

79 |
80 |
81 | 82 | 83 |
84 | 85 |
86 |
87 |

First featurette heading. It'll blow your mind.

88 |

Donec ullamcorper nulla non metus auctor fringilla. Vestibulum id ligula porta felis euismod semper. Praesent commodo cursus magna, vel scelerisque nisl consectetur. Fusce dapibus, tellus ac cursus commodo.

89 |
90 |
91 | Generic placeholder image 92 |
93 |
94 | 95 |
96 | 97 |
98 |
99 |

Oh yeah, it's that good. See for yourself.

100 |

Donec ullamcorper nulla non metus auctor fringilla. Vestibulum id ligula porta felis euismod semper. Praesent commodo cursus magna, vel scelerisque nisl consectetur. Fusce dapibus, tellus ac cursus commodo.

101 |
102 |
103 | Generic placeholder image 104 |
105 |
106 | 107 |
108 | 109 |
110 |
111 |

And lastly, this one. Checkmate.

112 |

Donec ullamcorper nulla non metus auctor fringilla. Vestibulum id ligula porta felis euismod semper. Praesent commodo cursus magna, vel scelerisque nisl consectetur. Fusce dapibus, tellus ac cursus commodo.

113 |
114 |
115 | Generic placeholder image 116 |
117 |
118 | 119 |
120 | 121 | 122 | 123 | 124 |
-------------------------------------------------------------------------------- /recipes/vscode-integration/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.1.0", 3 | "command": "assemble", 4 | "isShellCommand": true, 5 | "args": [], 6 | "showOutput": "always", 7 | "tasks": [ 8 | { 9 | "taskName": "build", 10 | "args": [], 11 | "isBuildCommand": true, 12 | "isWatching": false 13 | }, 14 | { 15 | "taskName": "start", 16 | "args": [], 17 | "isBuildCommand": false, 18 | "isWatching": true 19 | }, 20 | { 21 | "taskName": "publish", 22 | "args": [], 23 | "isBuildCommand": false, 24 | "isWatching": false 25 | } 26 | ] 27 | } -------------------------------------------------------------------------------- /recipes/vscode-integration/README.md: -------------------------------------------------------------------------------- 1 | ## VS Code Integration 2 | 3 | > This recipe demonstrates how to wire assemble to VS Code. 4 | 5 | **Set up some tasks in your `assemblefile.js`** 6 | 7 | These are just placeholder tasks for demonstration purposes. 8 | 9 | ```js 10 | 11 | 'use strict'; 12 | var assemble = require( 'assemble' ); 13 | 14 | var app = assemble(); 15 | 16 | app.task('default', ['build'], function (cb) { 17 | console.log('default task...'); 18 | cb(); 19 | }); 20 | 21 | app.task( 'start', function () { 22 | console.log("Here is where you could do some browsersync stuff..."); 23 | }); 24 | 25 | app.task('build', function (cb) { 26 | console.log('building...'); 27 | cb(); 28 | }); 29 | 30 | app.task('publish', function (cb) { 31 | console.log('publishing...'); 32 | cb(); 33 | }); 34 | 35 | module.exports = app; 36 | 37 | ``` 38 | 39 | **Defining the VS Code Commands:** 40 | 41 | To enable the ability to launch these tasks from the VS Code command palette 42 | you will need to configure the task runner. The easiest way to do this is to 43 | select `Configure Task Runner` from the command palette. 44 | 45 | ```json 46 | { 47 | "version": "0.1.0", 48 | "command": "assemble", 49 | "isShellCommand": true, 50 | "args": [], 51 | "showOutput": "always", 52 | "tasks": [ 53 | { 54 | "taskName": "build", 55 | "args": [], 56 | "isBuildCommand": true, 57 | "isWatching": false 58 | }, 59 | { 60 | "taskName": "start", 61 | "args": [], 62 | "isBuildCommand": false, 63 | "isWatching": true 64 | }, 65 | { 66 | "taskName": "publish", 67 | "args": [], 68 | "isBuildCommand": false, 69 | "isWatching": false 70 | } 71 | ] 72 | } 73 | ``` 74 | 75 | With this `tasks.json` added to the .vscode folder, the `build`, `start` and `publish` will be available from the command palette. 76 | 77 | More detailed information on VS Code tasks can be found in this article: [Integrate with External Tools via Tasks](http://code.visualstudio.com/docs/editor/tasks) 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /recipes/vscode-integration/assemblefile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var assemble = require( 'assemble' ); 3 | 4 | var app = assemble(); 5 | 6 | app.task( 'default', ['build'], function ( cb ) { 7 | console.log( 'default task...' ); 8 | cb(); 9 | } ); 10 | 11 | app.task( 'start', function () { 12 | console.log( 'Here is where you could do some browsersync stuff...' ); 13 | } ); 14 | 15 | app.task( 'build', function ( cb ) { 16 | console.log( 'building...' ); 17 | cb(); 18 | } ); 19 | 20 | app.task( 'publish', function ( cb ) { 21 | console.log( 'publishing...' ); 22 | cb(); 23 | } ); 24 | 25 | module.exports = app; 26 | -------------------------------------------------------------------------------- /recipes/vscode-integration/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vscode-integration", 3 | "version": "1.0.0", 4 | "description": "example of how to use assemble with VSCode", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 0", 8 | "build": "assemble build", 9 | "start": "assemble", 10 | "deploy": "assemble publish" 11 | }, 12 | "author": "ITLackey", 13 | "license": "ISC", 14 | "devDependencies": { 15 | "assemble": "^0.14.0" 16 | } 17 | } 18 | --------------------------------------------------------------------------------