├── .gitignore ├── README.md ├── app ├── app.js ├── components │ ├── about.jade │ ├── demoComponent │ │ ├── demoComponent.jade │ │ └── demoComponentDirective.js │ └── home.jade ├── img │ ├── socials-s34e775ff01.png │ └── socials │ │ ├── fb.png │ │ ├── git.png │ │ ├── in.png │ │ ├── tw.png │ │ ├── vk.png │ │ └── you.png ├── index.jade └── scss │ ├── adjustment │ ├── _layouts.scss │ ├── _media.scss │ ├── _mixins.scss │ ├── _normalize.scss │ └── _varibles.scss │ ├── app.scss │ └── sections │ └── _main-page.scss ├── bower.json ├── cover.jpg ├── gulpfile.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | dist.dev/ 2 | dist.prod/ 3 | # Created by .ignore support plugin (hsz.mobi) 4 | ### Yeoman template 5 | node_modules/ 6 | bower_components/ 7 | *.log 8 | 9 | build/ 10 | dist/ 11 | ### JetBrains template 12 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio 13 | 14 | *.iml 15 | 16 | ## Directory-based project format: 17 | .idea/ 18 | # if you remove the above rule, at least ignore the following: 19 | 20 | # User-specific stuff: 21 | # .idea/workspace.xml 22 | # .idea/tasks.xml 23 | # .idea/dictionaries 24 | 25 | # Sensitive or high-churn files: 26 | # .idea/dataSources.ids 27 | # .idea/dataSources.xml 28 | # .idea/sqlDataSources.xml 29 | # .idea/dynamic.xml 30 | # .idea/uiDesigner.xml 31 | 32 | # Gradle: 33 | # .idea/gradle.xml 34 | # .idea/libraries 35 | 36 | # Mongo Explorer plugin: 37 | # .idea/mongoSettings.xml 38 | 39 | ## File-based project format: 40 | *.ipr 41 | *.iws 42 | 43 | ## Plugin-specific files: 44 | 45 | # IntelliJ 46 | /out/ 47 | 48 | # mpeltonen/sbt-idea plugin 49 | .idea_modules/ 50 | 51 | # JIRA plugin 52 | atlassian-ide-plugin.xml 53 | 54 | # Crashlytics plugin (for Android Studio and IntelliJ) 55 | com_crashlytics_export_strings.xml 56 | crashlytics.properties 57 | crashlytics-build.properties 58 | 59 | .sass-cache/ 60 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Angular + Gulp: Fast built 2 | ![AngularJS plus Gulp](cover.jpg) 3 | ## Installation 4 | 5 | Before running any Gulp tasks: 6 | 7 | 1. Check out this repository 8 | 2. Ensure you have **node** installed 9 | 4. Almost, ensure you have **ruby**, **compass** and **singularitygs** installed 10 | 3. Run `npm install` and `bower install` in the root directory 11 | 12 | ## Project Structure 13 | 14 | The project ships with a directory structure like: 15 | 16 | /angular-gulp 17 | |---- package.json 18 | |---- bower.json 19 | |---- gulpfile.js 20 | |---- /app 21 | | |---- index.jade 22 | | |---- app.js 23 | | |---- /scss 24 | | | |---- app.scss 25 | | ... 26 | | |---- /components 27 | | | 28 | | ... 29 | |---- (/dist.dev) 30 | |---- (/dist.prod) 31 | 32 | ## Gulp Tasks 33 | 34 | All of the following are available from the command line. 35 | 36 | ### Essential ones 37 | 38 | These tasks I use as part of my regular developments and deploy scripts: 39 | 40 | - __`gulp watch-dev`__ Clean, build, and watch live changes to the dev environment. Built sources are served directly by the dev server from /dist.dev. 41 | - __`gulp watch-prod`__ Clean, build, and watch live changes to the prod environment. Built sources are served directly by the dev server from /dist.prod. 42 | - __`gulp`__ Default task builds for dev. Built sources are put into /dist.dev, and can be served directly. 43 | -------------------------------------------------------------------------------- /app/app.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app', [ 6 | 'ui.router', 7 | 'app.demoComponent' 8 | ]) 9 | .config(appConfig); 10 | 11 | // @ngInject 12 | function appConfig($stateProvider, $urlRouterProvider) { 13 | console.log('=== Start Config ==='); 14 | 15 | $urlRouterProvider.otherwise('/'); 16 | 17 | $stateProvider 18 | .state('home', { 19 | url: '/', 20 | templateUrl: 'components/home.html' 21 | }); 22 | } 23 | 24 | })(); -------------------------------------------------------------------------------- /app/components/about.jade: -------------------------------------------------------------------------------- 1 | // 2 | Created by severenit on 30/09/15. 3 | 4 | -------------------------------------------------------------------------------- /app/components/demoComponent/demoComponent.jade: -------------------------------------------------------------------------------- 1 | h3 2 | | This is a demo component. -------------------------------------------------------------------------------- /app/components/demoComponent/demoComponentDirective.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | angular 4 | .module('app.demoComponent', []) 5 | .directive('demoComponent', demoComponentFn); 6 | 7 | // @ngInject 8 | function demoComponentFn() { 9 | return { 10 | restrict: 'A', 11 | templateUrl: 'components/demoComponent/demoComponent.html' 12 | }; 13 | } 14 | })(); -------------------------------------------------------------------------------- /app/components/home.jade: -------------------------------------------------------------------------------- 1 | h2 2 | | Home page 3 | p 4 | div(demo-component='') 5 | 6 | -------------------------------------------------------------------------------- /app/img/socials-s34e775ff01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Severenit/angular-gulp/c2c8c59831c65bbc5ea346cacfffcb0522d95a4c/app/img/socials-s34e775ff01.png -------------------------------------------------------------------------------- /app/img/socials/fb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Severenit/angular-gulp/c2c8c59831c65bbc5ea346cacfffcb0522d95a4c/app/img/socials/fb.png -------------------------------------------------------------------------------- /app/img/socials/git.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Severenit/angular-gulp/c2c8c59831c65bbc5ea346cacfffcb0522d95a4c/app/img/socials/git.png -------------------------------------------------------------------------------- /app/img/socials/in.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Severenit/angular-gulp/c2c8c59831c65bbc5ea346cacfffcb0522d95a4c/app/img/socials/in.png -------------------------------------------------------------------------------- /app/img/socials/tw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Severenit/angular-gulp/c2c8c59831c65bbc5ea346cacfffcb0522d95a4c/app/img/socials/tw.png -------------------------------------------------------------------------------- /app/img/socials/vk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Severenit/angular-gulp/c2c8c59831c65bbc5ea346cacfffcb0522d95a4c/app/img/socials/vk.png -------------------------------------------------------------------------------- /app/img/socials/you.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Severenit/angular-gulp/c2c8c59831c65bbc5ea346cacfffcb0522d95a4c/app/img/socials/you.png -------------------------------------------------------------------------------- /app/index.jade: -------------------------------------------------------------------------------- 1 | doctype html 2 | html(ng-app='app') 3 | head 4 | meta(charset='UTF-8') 5 | title Angular + Gulp 6 | // inject:css 7 | // endinject 8 | body 9 | h1 Angular + Gulp 10 | ui-view 11 | .p 12 | | This is Jade file and more and more... 13 | .row 14 | i.socials__item_vk 15 | i.socials__item_fb 16 | i.socials__item_tw 17 | i.socials__item_in 18 | i.socials__item_git 19 | i.socials__item_you 20 | // bower:js 21 | // endinject 22 | // inject:js 23 | // endinject -------------------------------------------------------------------------------- /app/scss/adjustment/_layouts.scss: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: Arial; 3 | line-height: 1.425; 4 | 5 | @include desktop { 6 | font-size: 16px; 7 | } 8 | 9 | @include laptop { 10 | font-size: 16px; 11 | } 12 | 13 | @include tablet { 14 | font-size: 14px; 15 | } 16 | 17 | @include phone { 18 | font-size: 12px; 19 | } 20 | } -------------------------------------------------------------------------------- /app/scss/adjustment/_media.scss: -------------------------------------------------------------------------------- 1 | $grids: 12; 2 | $gutters: 1/3; 3 | 4 | @mixin desktop { 5 | @media (max-width: 1200px) { 6 | @content 7 | } 8 | } 9 | 10 | @mixin laptop { 11 | @media (max-width: 992px) { 12 | @content 13 | } 14 | } 15 | 16 | 17 | @mixin tablet { 18 | @media (max-width: 768px) { 19 | @content 20 | } 21 | } 22 | 23 | 24 | @mixin phone { 25 | @media (max-width: 480px) { 26 | @content 27 | } 28 | } 29 | 30 | @function em($target, $context: $base-font-size) { 31 | @if $target == 0 {@return 0} 32 | @return $target / $context + 0em; 33 | } 34 | 35 | // EXAMPLE 36 | //@include grid-span(12, 1); 37 | //@include float-span(4, $gutter: 0); 38 | 39 | -------------------------------------------------------------------------------- /app/scss/adjustment/_mixins.scss: -------------------------------------------------------------------------------- 1 | /* --------- mixins --------- */ 2 | 3 | @mixin inlineblock { 4 | display: inline-block; 5 | vertical-align: top; 6 | } 7 | 8 | @mixin clearfix { 9 | &:before, 10 | &:after { 11 | content: ""; 12 | display: table; 13 | } 14 | 15 | &:after { 16 | clear: both; 17 | } 18 | } 19 | 20 | @mixin border-radius($radius: 4px) { 21 | -webkit-border-radius: $radius; 22 | -moz-border-radius: $radius; 23 | border-radius: $radius; 24 | 25 | -moz-background-clip: padding; 26 | -webkit-background-clip: padding-box; 27 | background-clip: padding-box; 28 | } 29 | 30 | @mixin box-shadow($string...) { 31 | -webkit-box-shadow: $string; 32 | -moz-box-shadow: $string; 33 | box-shadow: $string; 34 | } 35 | 36 | @mixin transition($transition...) { 37 | -webkit-transition: $transition; 38 | -moz-transition: $transition; 39 | -ms-transition: $transition; 40 | -o-transition: $transition; 41 | transition: $transition; 42 | } 43 | 44 | @mixin placecolor($color: #000000) { 45 | &::-webkit-input-placeholder { 46 | color: $color; 47 | } 48 | &:-moz-placeholder { 49 | color: $color; 50 | } 51 | &::-moz-placeholder { 52 | color: $color; 53 | } 54 | &:-ms-input-placeholder { 55 | color: $color; 56 | } 57 | } 58 | 59 | @mixin vertical-gradient($top-color: #ffffff, $bottom-color: #000000) { 60 | background-color: $top-color; 61 | background-image: -webkit-gradient(linear, left top, left bottom, from($top-color), to($bottom-color)); /* Chrome, Safari 4+ */ 62 | background-image: -webkit-linear-gradient(top, $top-color, $bottom-color); /* Chrome 10-25, iOS 5+, Safari 5.1+ */ 63 | background-image: -moz-linear-gradient(top, $top-color, $bottom-color); /* Firefox 3.6-15 */ 64 | background-image: -o-linear-gradient(top, $top-color, $bottom-color); /* Opera 11.10-12.00 */ 65 | background-image: linear-gradient(to bottom, $top-color, $bottom-color); /* Chrome 26, Firefox 16+, IE 10+, Opera 12.10+ */ 66 | filter: progid:DXImageTransform.Microsoft.gradient(startColorStr=$top-color, EndColorStr=$bottom-color); 67 | } 68 | 69 | @mixin transform($transforms) { 70 | -moz-transform: $transforms; 71 | -o-transform: $transforms; 72 | -ms-transform: $transforms; 73 | -webkit-transform: $transforms; 74 | transform: $transforms; 75 | } 76 | 77 | /* --------- flexbox --------- */ 78 | 79 | @mixin flexbox { 80 | display: -webkit-box; 81 | display: -webkit-flex; 82 | display: -moz-flex; 83 | display: -ms-flexbox; 84 | display: flex; 85 | } 86 | 87 | @mixin inline-flex { 88 | display: -webkit-inline-box; 89 | display: -webkit-inline-flex; 90 | display: -moz-inline-flex; 91 | display: -ms-inline-flexbox; 92 | display: inline-flex; 93 | } 94 | 95 | @mixin flex-direction($value: row) { 96 | @if $value == row-reverse { 97 | -webkit-box-direction: reverse; 98 | -webkit-box-orient: horizontal; 99 | } @else if $value == column { 100 | -webkit-box-direction: normal; 101 | -webkit-box-orient: vertical; 102 | } @else if $value == column-reverse { 103 | -webkit-box-direction: reverse; 104 | -webkit-box-orient: vertical; 105 | } @else { 106 | -webkit-box-direction: normal; 107 | -webkit-box-orient: horizontal; 108 | } 109 | -webkit-flex-direction: $value; 110 | -moz-flex-direction: $value; 111 | -ms-flex-direction: $value; 112 | flex-direction: $value; 113 | } 114 | 115 | @mixin flex-wrap($value: nowrap) { 116 | // No Webkit Box fallback. 117 | -webkit-flex-wrap: $value; 118 | -moz-flex-wrap: $value; 119 | @if $value == nowrap { 120 | -ms-flex-wrap: none; 121 | } @else { 122 | -ms-flex-wrap: $value; 123 | } 124 | flex-wrap: $value; 125 | } 126 | 127 | @mixin flex-flow($values: (row nowrap)) { 128 | // No Webkit Box fallback. 129 | -webkit-flex-flow: $values; 130 | -moz-flex-flow: $values; 131 | -ms-flex-flow: $values; 132 | flex-flow: $values; 133 | } 134 | 135 | @mixin order($int: 0) { 136 | -webkit-box-ordinal-group: $int + 1; 137 | -webkit-order: $int; 138 | -moz-order: $int; 139 | -ms-flex-order: $int; 140 | order: $int; 141 | } 142 | 143 | @mixin flex-grow($int: 0) { 144 | -webkit-box-flex: $int; 145 | -webkit-flex-grow: $int; 146 | -moz-flex-grow: $int; 147 | -ms-flex-positive: $int; 148 | flex-grow: $int; 149 | } 150 | 151 | @mixin flex-shrink($int: 1) { 152 | -webkit-flex-shrink: $int; 153 | -moz-flex-shrink: $int; 154 | -ms-flex-negative: $int; 155 | flex-shrink: $int; 156 | } 157 | 158 | @mixin flex-basis($value: auto) { 159 | -webkit-flex-basis: $value; 160 | -moz-flex-basis: $value; 161 | -ms-flex-preferred-size: $value; 162 | flex-basis: $value; 163 | } 164 | 165 | @mixin flex($fg: 1, $fs: null, $fb: null) { 166 | $fg-boxflex: $fg; 167 | @if type-of($fg) == 'list' { 168 | $fg-boxflex: nth($fg, 1); 169 | } 170 | 171 | -webkit-box-flex: $fg-boxflex; 172 | -webkit-flex: $fg $fs $fb; 173 | -moz-box-flex: $fg-boxflex; 174 | -moz-flex: $fg $fs $fb; 175 | -ms-flex: $fg $fs $fb; 176 | flex: $fg $fs $fb; 177 | } 178 | 179 | @mixin justify-content($value: flex-start) { 180 | @if $value == flex-start { 181 | -webkit-box-pack: start; 182 | -ms-flex-pack: start; 183 | } @else if $value == flex-end { 184 | -webkit-box-pack: end; 185 | -ms-flex-pack: end; 186 | } @else if $value == space-between { 187 | -webkit-box-pack: justify; 188 | -ms-flex-pack: justify; 189 | } @else if $value == space-around { 190 | -ms-flex-pack: distribute; 191 | } @else { 192 | -webkit-box-pack: $value; 193 | -ms-flex-pack: $value; 194 | } 195 | -webkit-justify-content: $value; 196 | -moz-justify-content: $value; 197 | justify-content: $value; 198 | } 199 | 200 | @mixin align-items($value: stretch) { 201 | @if $value == flex-start { 202 | -webkit-box-align: start; 203 | -ms-flex-align: start; 204 | } @else if $value == flex-end { 205 | -webkit-box-align: end; 206 | -ms-flex-align: end; 207 | } @else { 208 | -webkit-box-align: $value; 209 | -ms-flex-align: $value; 210 | } 211 | -webkit-align-items: $value; 212 | -moz-align-items: $value; 213 | align-items: $value; 214 | } 215 | 216 | @mixin align-self($value: auto) { 217 | // No Webkit Box Fallback. 218 | -webkit-align-self: $value; 219 | -moz-align-self: $value; 220 | @if $value == flex-start { 221 | -ms-flex-item-align: start; 222 | } @else if $value == flex-end { 223 | -ms-flex-item-align: end; 224 | } @else { 225 | -ms-flex-item-align: $value; 226 | } 227 | align-self: $value; 228 | } 229 | 230 | @mixin align-content($value: stretch) { 231 | -webkit-align-content: $value; 232 | -moz-align-content: $value; 233 | @if $value == flex-start { 234 | -ms-flex-line-pack: start; 235 | } @else if $value == flex-end { 236 | -ms-flex-line-pack: end; 237 | } @else { 238 | -ms-flex-line-pack: $value; 239 | } 240 | align-content: $value; 241 | } 242 | 243 | /* --------- compass sprites --------- */ 244 | 245 | @mixin get-sprite($map, $sprite, $repeat: no-repeat, $height: true, $width: true) { 246 | $sprite-image: sprite-file($map, $sprite); 247 | $sprite-map: sprite-url($map); 248 | $sprite-position: sprite-position($map, $sprite); 249 | $sprite-layout: smart; 250 | 251 | background: $sprite-map $sprite-position $repeat; 252 | 253 | @if ($height == true) { 254 | $sprite-height: image-height($sprite-image); 255 | height: $sprite-height; 256 | } 257 | 258 | @if ($width == true) { 259 | $sprite-width: image-width($sprite-image); 260 | width: $sprite-width; 261 | } 262 | } 263 | //exsample 264 | //$socials: vk, fb, tw, od; 265 | //$socials-map: sprite-map('socials/*.png', $spacing: 5px); 266 | // 267 | //@each $item in $socials { 268 | // .socials__item_#{$item} { 269 | // @include get-sprite($socials-map, $item); 270 | // } 271 | //} 272 | // 273 | //.vkontakteg { 274 | // @include get-sprite($socials-map, vk); 275 | //} 276 | 277 | -------------------------------------------------------------------------------- /app/scss/adjustment/_normalize.scss: -------------------------------------------------------------------------------- 1 | /*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */ 2 | 3 | /** 4 | * 1. Set default font family to sans-serif. 5 | * 2. Prevent iOS and IE text size adjust after device orientation change, 6 | * without disabling user zoom. 7 | */ 8 | 9 | html { 10 | font-family: sans-serif; /* 1 */ 11 | -ms-text-size-adjust: 100%; /* 2 */ 12 | -webkit-text-size-adjust: 100%; /* 2 */ 13 | } 14 | 15 | /** 16 | * Remove default margin. 17 | */ 18 | 19 | body { 20 | margin: 0; 21 | } 22 | 23 | /* HTML5 display definitions 24 | ========================================================================== */ 25 | 26 | /** 27 | * Correct `block` display not defined for any HTML5 element in IE 8/9. 28 | * Correct `block` display not defined for `details` or `summary` in IE 10/11 29 | * and Firefox. 30 | * Correct `block` display not defined for `main` in IE 11. 31 | */ 32 | 33 | article, 34 | aside, 35 | details, 36 | figcaption, 37 | figure, 38 | footer, 39 | header, 40 | hgroup, 41 | main, 42 | menu, 43 | nav, 44 | section, 45 | summary { 46 | display: block; 47 | } 48 | 49 | /** 50 | * 1. Correct `inline-block` display not defined in IE 8/9. 51 | * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. 52 | */ 53 | 54 | audio, 55 | canvas, 56 | progress, 57 | video { 58 | display: inline-block; /* 1 */ 59 | vertical-align: baseline; /* 2 */ 60 | } 61 | 62 | /** 63 | * Prevent modern browsers from displaying `audio` without controls. 64 | * Remove excess height in iOS 5 devices. 65 | */ 66 | 67 | audio:not([controls]) { 68 | display: none; 69 | height: 0; 70 | } 71 | 72 | /** 73 | * Address `[hidden]` styling not present in IE 8/9/10. 74 | * Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22. 75 | */ 76 | 77 | [hidden], 78 | template { 79 | display: none; 80 | } 81 | 82 | /* Links 83 | ========================================================================== */ 84 | 85 | /** 86 | * Remove the gray background color from active links in IE 10. 87 | */ 88 | 89 | a { 90 | background-color: transparent; 91 | } 92 | 93 | /** 94 | * Improve readability of focused elements when they are also in an 95 | * active/hover state. 96 | */ 97 | 98 | a:active, 99 | a:hover { 100 | outline: 0; 101 | } 102 | 103 | /* Text-level semantics 104 | ========================================================================== */ 105 | 106 | /** 107 | * Address styling not present in IE 8/9/10/11, Safari, and Chrome. 108 | */ 109 | 110 | abbr[title] { 111 | border-bottom: 1px dotted; 112 | } 113 | 114 | /** 115 | * Address style set to `bolder` in Firefox 4+, Safari, and Chrome. 116 | */ 117 | 118 | b, 119 | strong { 120 | font-weight: bold; 121 | } 122 | 123 | /** 124 | * Address styling not present in Safari and Chrome. 125 | */ 126 | 127 | dfn { 128 | font-style: italic; 129 | } 130 | 131 | /** 132 | * Address variable `h1` font-size and margin within `section` and `article` 133 | * contexts in Firefox 4+, Safari, and Chrome. 134 | */ 135 | 136 | h1 { 137 | font-size: 2em; 138 | margin: 0.67em 0; 139 | } 140 | 141 | /** 142 | * Address styling not present in IE 8/9. 143 | */ 144 | 145 | mark { 146 | background: #ff0; 147 | color: #000; 148 | } 149 | 150 | /** 151 | * Address inconsistent and variable font size in all browsers. 152 | */ 153 | 154 | small { 155 | font-size: 80%; 156 | } 157 | 158 | /** 159 | * Prevent `sub` and `sup` affecting `line-height` in all browsers. 160 | */ 161 | 162 | sub, 163 | sup { 164 | font-size: 75%; 165 | line-height: 0; 166 | position: relative; 167 | vertical-align: baseline; 168 | } 169 | 170 | sup { 171 | top: -0.5em; 172 | } 173 | 174 | sub { 175 | bottom: -0.25em; 176 | } 177 | 178 | /* Embedded content 179 | ========================================================================== */ 180 | 181 | /** 182 | * Remove border when inside `a` element in IE 8/9/10. 183 | */ 184 | 185 | img { 186 | border: 0; 187 | } 188 | 189 | /** 190 | * Correct overflow not hidden in IE 9/10/11. 191 | */ 192 | 193 | svg:not(:root) { 194 | overflow: hidden; 195 | } 196 | 197 | /* Grouping content 198 | ========================================================================== */ 199 | 200 | /** 201 | * Address margin not present in IE 8/9 and Safari. 202 | */ 203 | 204 | figure { 205 | margin: 1em 40px; 206 | } 207 | 208 | /** 209 | * Address differences between Firefox and other browsers. 210 | */ 211 | 212 | hr { 213 | box-sizing: content-box; 214 | height: 0; 215 | } 216 | 217 | /** 218 | * Contain overflow in all browsers. 219 | */ 220 | 221 | pre { 222 | overflow: auto; 223 | } 224 | 225 | /** 226 | * Address odd `em`-unit font size rendering in all browsers. 227 | */ 228 | 229 | code, 230 | kbd, 231 | pre, 232 | samp { 233 | font-family: monospace, monospace; 234 | font-size: 1em; 235 | } 236 | 237 | /* Forms 238 | ========================================================================== */ 239 | 240 | /** 241 | * Known limitation: by default, Chrome and Safari on OS X allow very limited 242 | * styling of `select`, unless a `border` property is set. 243 | */ 244 | 245 | /** 246 | * 1. Correct color not being inherited. 247 | * Known issue: affects color of disabled elements. 248 | * 2. Correct font properties not being inherited. 249 | * 3. Address margins set differently in Firefox 4+, Safari, and Chrome. 250 | */ 251 | 252 | button, 253 | input, 254 | optgroup, 255 | select, 256 | textarea { 257 | color: inherit; /* 1 */ 258 | font: inherit; /* 2 */ 259 | margin: 0; /* 3 */ 260 | } 261 | 262 | /** 263 | * Address `overflow` set to `hidden` in IE 8/9/10/11. 264 | */ 265 | 266 | button { 267 | overflow: visible; 268 | } 269 | 270 | /** 271 | * Address inconsistent `text-transform` inheritance for `button` and `select`. 272 | * All other form control elements do not inherit `text-transform` values. 273 | * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. 274 | * Correct `select` style inheritance in Firefox. 275 | */ 276 | 277 | button, 278 | select { 279 | text-transform: none; 280 | } 281 | 282 | /** 283 | * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` 284 | * and `video` controls. 285 | * 2. Correct inability to style clickable `input` types in iOS. 286 | * 3. Improve usability and consistency of cursor style between image-type 287 | * `input` and others. 288 | */ 289 | 290 | button, 291 | html input[type="button"], /* 1 */ 292 | input[type="reset"], 293 | input[type="submit"] { 294 | -webkit-appearance: button; /* 2 */ 295 | cursor: pointer; /* 3 */ 296 | } 297 | 298 | /** 299 | * Re-set default cursor for disabled elements. 300 | */ 301 | 302 | button[disabled], 303 | html input[disabled] { 304 | cursor: default; 305 | } 306 | 307 | /** 308 | * Remove inner padding and border in Firefox 4+. 309 | */ 310 | 311 | button::-moz-focus-inner, 312 | input::-moz-focus-inner { 313 | border: 0; 314 | padding: 0; 315 | } 316 | 317 | /** 318 | * Address Firefox 4+ setting `line-height` on `input` using `!important` in 319 | * the UA stylesheet. 320 | */ 321 | 322 | input { 323 | line-height: normal; 324 | } 325 | 326 | /** 327 | * It's recommended that you don't attempt to style these elements. 328 | * Firefox's implementation doesn't respect box-sizing, padding, or width. 329 | * 330 | * 1. Address box sizing set to `content-box` in IE 8/9/10. 331 | * 2. Remove excess padding in IE 8/9/10. 332 | */ 333 | 334 | input[type="checkbox"], 335 | input[type="radio"] { 336 | box-sizing: border-box; /* 1 */ 337 | padding: 0; /* 2 */ 338 | } 339 | 340 | /** 341 | * Fix the cursor style for Chrome's increment/decrement buttons. For certain 342 | * `font-size` values of the `input`, it causes the cursor style of the 343 | * decrement button to change from `default` to `text`. 344 | */ 345 | 346 | input[type="number"]::-webkit-inner-spin-button, 347 | input[type="number"]::-webkit-outer-spin-button { 348 | height: auto; 349 | } 350 | 351 | /** 352 | * 1. Address `appearance` set to `searchfield` in Safari and Chrome. 353 | * 2. Address `box-sizing` set to `border-box` in Safari and Chrome. 354 | */ 355 | 356 | input[type="search"] { 357 | -webkit-appearance: textfield; /* 1 */ 358 | box-sizing: content-box; /* 2 */ 359 | } 360 | 361 | /** 362 | * Remove inner padding and search cancel button in Safari and Chrome on OS X. 363 | * Safari (but not Chrome) clips the cancel button when the search input has 364 | * padding (and `textfield` appearance). 365 | */ 366 | 367 | input[type="search"]::-webkit-search-cancel-button, 368 | input[type="search"]::-webkit-search-decoration { 369 | -webkit-appearance: none; 370 | } 371 | 372 | /** 373 | * Define consistent border, margin, and padding. 374 | */ 375 | 376 | fieldset { 377 | border: 1px solid #c0c0c0; 378 | margin: 0 2px; 379 | padding: 0.35em 0.625em 0.75em; 380 | } 381 | 382 | /** 383 | * 1. Correct `color` not being inherited in IE 8/9/10/11. 384 | * 2. Remove padding so people aren't caught out if they zero out fieldsets. 385 | */ 386 | 387 | legend { 388 | border: 0; /* 1 */ 389 | padding: 0; /* 2 */ 390 | } 391 | 392 | /** 393 | * Remove default vertical scrollbar in IE 8/9/10/11. 394 | */ 395 | 396 | textarea { 397 | overflow: auto; 398 | } 399 | 400 | /** 401 | * Don't inherit the `font-weight` (applied by a rule above). 402 | * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. 403 | */ 404 | 405 | optgroup { 406 | font-weight: bold; 407 | } 408 | 409 | /* Tables 410 | ========================================================================== */ 411 | 412 | /** 413 | * Remove most spacing between table cells. 414 | */ 415 | 416 | table { 417 | border-collapse: collapse; 418 | border-spacing: 0; 419 | } 420 | 421 | td, 422 | th { 423 | padding: 0; 424 | } 425 | -------------------------------------------------------------------------------- /app/scss/adjustment/_varibles.scss: -------------------------------------------------------------------------------- 1 | $base-font-size: 16px; -------------------------------------------------------------------------------- /app/scss/app.scss: -------------------------------------------------------------------------------- 1 | @import "compass"; 2 | @import "singularitygs"; 3 | 4 | /* ----- adjustment ----- */ 5 | @import "adjustment/varibles"; 6 | @import "adjustment/mixins"; 7 | @import "adjustment/media"; 8 | @import "adjustment/layouts"; 9 | 10 | /* ----- sections ----- */ 11 | @import "sections/main-page"; 12 | 13 | @include sgs-change('debug', false); 14 | 15 | .container { 16 | @include background-grid($color: #ccc); 17 | } 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/scss/sections/_main-page.scss: -------------------------------------------------------------------------------- 1 | $socials: vk, fb, tw, in, git, you; 2 | $socials-map: sprite-map('socials/*.png', $spacing: 5px); 3 | 4 | @each $item in $socials { 5 | .socials__item_#{$item} { 6 | @include get-sprite($socials-map, $item); 7 | display: inline-block; 8 | vertical-align: middle; 9 | } 10 | } -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-gulp", 3 | "version": "0.0.0", 4 | "authors": [ 5 | "Zar Zakharov " 6 | ], 7 | "keywords": [ 8 | "angular", 9 | "gulp", 10 | "loftblog" 11 | ], 12 | "license": "MIT", 13 | "ignore": [ 14 | "**/.*", 15 | "node_modules", 16 | "bower_components", 17 | "test", 18 | "tests" 19 | ], 20 | "dependencies": { 21 | "angular": "~1.4.6", 22 | "angular-ui-router": "~0.2.15", 23 | "jquery": "~2.1.4" 24 | }, 25 | "devDependencies": { 26 | "angular-mocks": "~1.4.6" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Severenit/angular-gulp/c2c8c59831c65bbc5ea346cacfffcb0522d95a4c/cover.jpg -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var plugins = require('gulp-load-plugins')(); 3 | var del = require('del'); 4 | var es = require('event-stream'); 5 | var bowerFiles = require('main-bower-files'); 6 | var browserSync = require('browser-sync'); 7 | // If you use jade in your project you must set variable 'useJade' equal 'TRUE' 8 | var useJade = true; 9 | // If we want see error logs 10 | var log = function (error) { 11 | console.log([ 12 | '', 13 | "----------ERROR MESSAGE START----------", 14 | ("[" + error.name + " in " + error.plugin + "]"), 15 | error.message, 16 | "----------ERROR MESSAGE END----------", 17 | '' 18 | ].join('\n')); 19 | this.end(); 20 | }; 21 | /* = = = 22 | | 23 | | PATH SEGMENT 24 | | 25 | = = = */ 26 | var paths = { 27 | scripts: 'app/**/*.js', //path for our js files 28 | styles: ['./app/scss/**/*.css', './app/scss/**/*.scss'], //path for our *.css and *.scss 29 | images: 'app/img/**/*', //path for our images 30 | index: 'app/index.html', //path for our index.html 31 | indexJade: 'app/index.jade', //path for our index.jade 32 | partials: ['app/**/*.html', '!app/index.html'], //path for our *.html files 33 | partialsJade: ['app/**/*.jade', '!app/index.jade'], //path for our *.jade files 34 | distDev: 'dist.dev', //path for our DEV directory 35 | distProd: 'dist.prod', //path for our PROD directory 36 | distDevCss: 'dist.dev/css', //path for our DEV directory and CSS folder 37 | distProdCss: 'dist.prod/css', //path for our PROD directory and CSS folder 38 | distDevImg: 'dist.dev/img', //path for our DEV directory and IMG folder 39 | distProdImg: 'dist.prod/img', //path for our DEV directory and IMG folder 40 | distScriptsProd: 'dist.prod/scripts' //path for our PROD directory and JS folder 41 | }; 42 | /* = = = 43 | | 44 | | PIPE SEGMENT 45 | | 46 | = = = */ 47 | var pipes = {}; 48 | // Sorts our scripts, first jQuery, and then angular 49 | pipes.orderedVendorScripts = function() { 50 | return plugins.order(['jquery.js', 'angular.js']); 51 | }; 52 | // Check our JS scripts through jsHint 53 | pipes.validatedAppScripts = function() { 54 | return gulp.src(paths.scripts) 55 | .pipe(plugins.jshint()) 56 | .pipe(plugins.jshint.reporter('jshint-stylish')); 57 | }; 58 | // Built index.jade file or gulp.src index.html 59 | pipes.buildIndexFile = function() { 60 | if (useJade) { 61 | return gulp.src(paths.indexJade) 62 | .pipe(plugins.plumber({ 63 | errorHandler: function (error) { 64 | console.log(error.message); 65 | this.emit('end'); 66 | }})) 67 | .pipe(plugins.jade()) 68 | .pipe(plugins.prettify({indent_size: 2})) 69 | } else { 70 | return gulp.src(paths.index); 71 | } 72 | }; 73 | /* = = = 74 | | DEV PIPE SEGMENT 75 | = = = */ 76 | // Copy all the scripts from the bower_components and then moves to DEV directory 77 | pipes.builtVendorScriptsDev = function() { 78 | return gulp.src(bowerFiles()) 79 | .pipe(gulp.dest(paths.distDev + '/bower_components')); 80 | }; 81 | // Built App Script and then moves to DEV directory 82 | pipes.builtAppScriptsDev = function() { 83 | return pipes.validatedAppScripts() 84 | .pipe(plugins.ngAnnotate()) // We use ngAnnotate for inject on Angular 85 | .pipe(plugins.concat('app.js')) 86 | .pipe(gulp.dest(paths.distDev)); 87 | }; 88 | // Built Style scss file 89 | pipes.builtStylesDev = function() { 90 | return gulp.src('./app/scss/**/*.scss') 91 | .pipe(plugins.plumber({ 92 | errorHandler: function (error) { 93 | console.log(error.message); 94 | this.emit('end'); 95 | }})) 96 | .pipe(plugins.compass({ 97 | sourcemap: true, 98 | css: paths.distDevCss, 99 | sass: './app/scss/', 100 | image: './app/img/', 101 | require: ['compass', 'singularitygs'] 102 | })) 103 | .pipe(plugins.cssUrlAdjuster({ 104 | replace: ['../../app/img','../img/'] //When we use sprite we have wrong path for our sprite, this is fixed 105 | })) 106 | .pipe(gulp.dest(paths.distDevCss)); 107 | }; 108 | // Built all others jade file or html files and then moves to DEV directory 109 | pipes.builtPartialsFilesDev = function() { 110 | if (useJade) { 111 | return gulp.src(paths.partialsJade) 112 | .pipe(plugins.plumber()) 113 | .pipe(plugins.jade()) 114 | .pipe(plugins.prettify({indent_size: 2})) 115 | .pipe(gulp.dest(paths.distDev)); 116 | } else { 117 | return gulp.src(paths.partials) 118 | .pipe(plugins.htmlhint({'doctype-first': false})) 119 | .pipe(plugins.htmlhint.reporter()) 120 | .pipe(gulp.dest(paths.distDev)); 121 | } 122 | }; 123 | // Copy images files and then moves to DEV directory 124 | pipes.processedImagesDev = function() { 125 | return gulp.src(paths.images) 126 | .pipe(gulp.dest(paths.distDevImg)); 127 | }; 128 | // Built all project 129 | pipes.builtIndexDev = function() { 130 | var orderedVendorScripts = pipes.builtVendorScriptsDev() 131 | .pipe(pipes.orderedVendorScripts()); 132 | var orderedAppScripts = pipes.builtAppScriptsDev(); 133 | var appStyles = pipes.builtStylesDev(); 134 | return pipes.buildIndexFile() 135 | .pipe(gulp.dest(paths.distDev)) // write first to get relative path for inject 136 | .pipe(plugins.inject(orderedVendorScripts, {relative: true, name: 'bower'})) 137 | .pipe(plugins.inject(orderedAppScripts, {relative: true})) 138 | .pipe(plugins.inject(appStyles, {relative: true})) 139 | .pipe(gulp.dest(paths.distDev)); 140 | }; 141 | // Run streaming Assembly 142 | pipes.builtAppDev = function() { 143 | return es.merge(pipes.builtIndexDev(), pipes.builtPartialsFilesDev(), pipes.processedImagesDev()); 144 | }; 145 | /* = = = 146 | | PROD PIPE SEGMENT 147 | = = = */ 148 | // Built all others jade file or html files and then moves to PROD directory, before we check our files through htmlHint 149 | pipes.builtPartialsFilesProd = function() { 150 | if (useJade) { 151 | return gulp.src(paths.partialsJade) 152 | .pipe(plugins.plumber()) 153 | .pipe(plugins.jade()) 154 | .pipe(plugins.prettify({indent_size: 2})) 155 | .pipe(plugins.htmlhint({'doctype-first': false})) 156 | .pipe(plugins.htmlhint.reporter()) 157 | .pipe(plugins.htmlmin({collapseWhitespace: true, removeComments: true})) 158 | .pipe(gulp.dest(paths.distProd)); 159 | } else { 160 | return gulp.src(paths.partials) 161 | .pipe(plugins.htmlhint({'doctype-first': false})) 162 | .pipe(plugins.htmlhint.reporter()) 163 | .pipe(plugins.htmlmin({collapseWhitespace: true, removeComments: true})) 164 | .pipe(gulp.dest(paths.distProd)); 165 | } 166 | }; 167 | // Built App Script concat, minification and then moves to PROD directory 168 | pipes.builtAppScriptsProd = function() { 169 | return pipes.validatedAppScripts() 170 | .pipe(plugins.ngAnnotate()) 171 | .pipe(plugins.concat('app.min.js')) 172 | .pipe(plugins.uglify()) 173 | .pipe(gulp.dest(paths.distScriptsProd)); 174 | }; 175 | // Copy all the scripts from the bower_components and then moves to PROD/scripts directory 176 | pipes.builtVendorScriptsProd = function() { 177 | return gulp.src(bowerFiles('**/*.js')) 178 | .pipe(pipes.orderedVendorScripts()) 179 | .pipe(plugins.concat('vendor.min.js')) 180 | .pipe(plugins.uglify()) 181 | .pipe(gulp.dest(paths.distScriptsProd)); 182 | }; 183 | // Built style scss file 184 | pipes.builtStylesProd = function() { 185 | return gulp.src('./app/scss/**/*.scss') 186 | .pipe(plugins.compass({ 187 | css: paths.distDevCss, 188 | sass: './app/scss/', 189 | image: './app/img/', 190 | require: ['compass', 'singularitygs'] 191 | })) 192 | .pipe(plugins.cssUrlAdjuster({ 193 | replace: ['../../app/img','../img/'] 194 | })) 195 | .pipe(plugins.minifyCss({compatibility: 'ie8'})) 196 | .pipe(plugins.rename('style.min.css')) 197 | .pipe(plugins.csso()) 198 | .pipe(gulp.dest(paths.distProdCss)); 199 | }; 200 | // Copy images files and then moves to DEV directory 201 | pipes.processedImagesProd = function() { 202 | return gulp.src(paths.images) 203 | .pipe(gulp.dest(paths.distProdImg)); 204 | }; 205 | // Built all project 206 | pipes.builtIndexProd = function() { 207 | var vendorScripts = pipes.builtVendorScriptsProd(); 208 | var appScripts = pipes.builtAppScriptsProd(); 209 | var appStyles = pipes.builtStylesProd(); 210 | return pipes.buildIndexFile() 211 | .pipe(gulp.dest(paths.distProd)) // write first to get relative path for inject 212 | .pipe(plugins.inject(vendorScripts, {relative: true, name: 'bower'})) 213 | .pipe(plugins.inject(appScripts, {relative: true})) 214 | .pipe(plugins.inject(appStyles, {relative: true})) 215 | .pipe(plugins.htmlmin({collapseWhitespace: true, removeComments: true})) 216 | .pipe(gulp.dest(paths.distProd)); 217 | }; 218 | // Run streaming Assembly 219 | pipes.builtAppProd = function() { 220 | return es.merge(pipes.builtIndexProd(), pipes.builtPartialsFilesProd(), pipes.processedImagesProd()); 221 | }; 222 | /* = = = 223 | | 224 | | TASK 225 | | 226 | = = = */ 227 | /* = = = 228 | | DEV TASKS 229 | = = = */ 230 | // removes all compiled dev files 231 | gulp.task('clean-dev', function() { 232 | return del(paths.distDev); 233 | }); 234 | // builds a complete prod environment 235 | gulp.task('build-app-dev', pipes.builtAppDev); 236 | // cleans and builds a complete dev environment 237 | gulp.task('clean-build-app-dev', ['clean-dev'], pipes.builtAppDev); 238 | // clean, build, and watch live changes to the dev environment 239 | gulp.task('watch-dev', ['clean-build-app-dev'], function() { 240 | var indexPath; 241 | var partialsPath; 242 | var reload = browserSync.reload; 243 | 244 | if (useJade) { 245 | indexPath = paths.indexJade; 246 | partialsPath = paths.partialsJade; 247 | } else { 248 | indexPath = paths.index; 249 | partialsPath = paths.partials; 250 | } 251 | // start browser-sync to auto-reload the dev server 252 | browserSync({ 253 | port: 8000, 254 | server: { 255 | baseDir: paths.distDev 256 | } 257 | }); 258 | 259 | // watch index 260 | gulp.watch(indexPath, function() { 261 | return pipes.builtIndexDev() 262 | .pipe(reload({stream: true})); 263 | }); 264 | 265 | // watch app scripts 266 | gulp.watch(paths.scripts, function() { 267 | return pipes.builtAppScriptsDev() 268 | .pipe(reload({stream: true})); 269 | }); 270 | 271 | // watch html partials 272 | gulp.watch(partialsPath, function() { 273 | return pipes.builtPartialsFilesDev() 274 | .pipe(reload({stream: true})); 275 | 276 | }); 277 | 278 | // watch styles 279 | gulp.watch(paths.styles, function() { 280 | return pipes.builtStylesDev() 281 | .pipe(reload({stream: true})); 282 | }); 283 | 284 | // watch images 285 | gulp.watch(paths.images, function() { 286 | return pipes.processedImagesDev() 287 | .pipe(reload({stream: true})); 288 | }); 289 | 290 | }); 291 | /* = = = 292 | | PROD TASKS 293 | = = = */ 294 | // removes all compiled prod files 295 | gulp.task('clean-prod', function() { 296 | return del(paths.distProd); 297 | }); 298 | // builds a complete prod environment 299 | gulp.task('build-app-prod', pipes.builtAppProd); 300 | // cleans and builds a complete prod environment 301 | gulp.task('clean-build-app-prod', ['clean-prod'], pipes.builtAppProd); 302 | // clean, build, and watch live changes to the prod environment 303 | gulp.task('watch-prod', ['clean-build-app-prod'], function() { 304 | var indexPath; 305 | var partialsPath; 306 | var reload = browserSync.reload; 307 | 308 | if (useJade) { 309 | indexPath = paths.indexJade; 310 | partialsPath = paths.partialsJade; 311 | } else { 312 | indexPath = paths.index; 313 | partialsPath = paths.partials; 314 | } 315 | // start browser-sync to auto-reload the dev server 316 | browserSync({ 317 | port: 8000, 318 | server: { 319 | baseDir: paths.distProd 320 | } 321 | }); 322 | 323 | // watch index 324 | gulp.watch(indexPath, function() { 325 | return pipes.builtIndexDev() 326 | .pipe(reload({stream: true})); 327 | }); 328 | 329 | // watch app scripts 330 | gulp.watch(paths.scripts, function() { 331 | return pipes.builtAppScriptsDev() 332 | .pipe(reload({stream: true})); 333 | }); 334 | 335 | // watch html partials 336 | gulp.watch(partialsPath, function() { 337 | return pipes.builtPartialsFilesDev() 338 | .pipe(reload({stream: true})); 339 | 340 | }); 341 | 342 | // watch styles 343 | gulp.watch(paths.styles, function() { 344 | return pipes.builtStylesDev() 345 | .pipe(reload({stream: true})); 346 | }); 347 | 348 | // watch images 349 | gulp.watch(paths.images, function() { 350 | return pipes.processedImagesDev() 351 | .pipe(reload({stream: true})); 352 | }); 353 | 354 | }); 355 | /* = = = 356 | | DEFAULT TASKS 357 | = = = */ 358 | // If we start only gulp command we built DEV folder and DEV server 359 | gulp.task('default', ['watch-dev']); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-gulp", 3 | "version": "1.0.0", 4 | "description": "Example of using gulp with an Angular project for an loftblog lesson", 5 | "scripts": { 6 | "test": "echo \"Error: no test specified\" && exit 1" 7 | }, 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/Severenit/angular-gulp.git" 11 | }, 12 | "keywords": [ 13 | "angular", 14 | "gulp", 15 | "loftblog" 16 | ], 17 | "author": "Zar Zakharov", 18 | "license": "MIT", 19 | "bugs": { 20 | "url": "https://github.com/Severenit/angular-gulp/issues" 21 | }, 22 | "homepage": "https://github.com/Severenit/angular-gulp", 23 | "devDependencies": { 24 | "browser-sync": "^2.9.6", 25 | "del": "^2.0.2", 26 | "event-stream": "^3.3.1", 27 | "gulp": "^3.9.0", 28 | "gulp-compass": "^2.1.0", 29 | "gulp-concat": "^2.6.0", 30 | "gulp-css-url-adjuster": "^0.2.3", 31 | "gulp-csso": "^1.0.0", 32 | "gulp-htmlhint": "^0.3.0", 33 | "gulp-htmlmin": "^1.1.4", 34 | "gulp-inject": "^3.0.0", 35 | "gulp-jade": "^1.1.0", 36 | "gulp-jshint": "^1.11.2", 37 | "gulp-load-plugins": "^1.0.0-rc.1", 38 | "gulp-minify-css": "^1.2.1", 39 | "gulp-ng-annotate": "^1.1.0", 40 | "gulp-order": "^1.1.1", 41 | "gulp-plumber": "^1.0.1", 42 | "gulp-prettify": "^0.3.0", 43 | "gulp-rename": "^1.2.2", 44 | "gulp-sass": "^2.0.4", 45 | "gulp-sourcemaps": "^1.6.0", 46 | "gulp-uglify": "^1.4.1", 47 | "jshint-stylish": "^2.0.1", 48 | "main-bower-files": "^2.9.0" 49 | } 50 | } 51 | --------------------------------------------------------------------------------