├── src ├── fonts │ └── .gitkeep ├── img │ ├── .gitkeep │ └── icons │ │ ├── fonts │ │ └── .gitkeep │ │ ├── svg │ │ └── .gitkeep │ │ └── raster │ │ └── .gitkeep ├── js │ ├── common.js │ └── index.js ├── pug │ ├── data │ │ └── .gitkeep │ ├── modules │ │ ├── _footer.pug │ │ └── _header.pug │ ├── index.pug │ ├── _mixins.pug │ └── _layout.pug └── sass │ ├── _helpers.scss │ ├── _fonts.scss │ ├── modules │ ├── _footer.scss │ ├── _header.scss │ ├── _headings.scss │ └── _container.scss │ ├── libs.scss │ ├── main.scss │ ├── _vars.scss │ ├── _base.scss │ └── _mixins.scss ├── .prettierignore ├── .stylelintignore ├── .browserslistrc ├── .gitignore ├── .babelrc ├── webpack ├── webpack.dev.js ├── webpack.prod.js └── webpack.common.js ├── .editorconfig ├── postcss.config.js ├── gulp ├── constants.js └── utils.js ├── .stylelintrc.json ├── package.json └── gulpfile.js /src/fonts/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/img/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/js/common.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/js/index.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/pug/data/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/sass/_helpers.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | dist 2 | -------------------------------------------------------------------------------- /src/img/icons/fonts/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/img/icons/svg/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/img/icons/raster/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/sass/_fonts.scss: -------------------------------------------------------------------------------- 1 | /* Font */ 2 | -------------------------------------------------------------------------------- /.stylelintignore: -------------------------------------------------------------------------------- 1 | 2 | node_modules 3 | dist 4 | -------------------------------------------------------------------------------- /src/sass/modules/_footer.scss: -------------------------------------------------------------------------------- 1 | /* Page footer */ 2 | -------------------------------------------------------------------------------- /src/sass/modules/_header.scss: -------------------------------------------------------------------------------- 1 | /* Page header */ 2 | -------------------------------------------------------------------------------- /src/pug/modules/_footer.pug: -------------------------------------------------------------------------------- 1 | footer.page-footer.page__footer 2 | -------------------------------------------------------------------------------- /src/pug/modules/_header.pug: -------------------------------------------------------------------------------- 1 | header.page-header.page__header 2 | -------------------------------------------------------------------------------- /.browserslistrc: -------------------------------------------------------------------------------- 1 | # Browsers that we support 2 | 3 | last 2 versions -------------------------------------------------------------------------------- /src/sass/modules/_headings.scss: -------------------------------------------------------------------------------- 1 | %heading { 2 | margin-top: 0; 3 | } 4 | -------------------------------------------------------------------------------- /src/sass/libs.scss: -------------------------------------------------------------------------------- 1 | @import "vars"; 2 | @import "normalize.css/normalize"; 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | ftp.json 4 | src/img/crop 5 | src/img/cropped 6 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env"], 3 | "plugins": ["@babel/plugin-transform-classes"] 4 | } 5 | -------------------------------------------------------------------------------- /src/pug/index.pug: -------------------------------------------------------------------------------- 1 | extends _layout 2 | 3 | block variables 4 | - var pageTitle = "Page title"; 5 | 6 | block content 7 | -------------------------------------------------------------------------------- /src/sass/main.scss: -------------------------------------------------------------------------------- 1 | @import "vars"; 2 | @import "mixins"; 3 | @import "fonts"; 4 | @import "base"; 5 | @import "modules/*.scss"; 6 | @import "helpers"; 7 | -------------------------------------------------------------------------------- /webpack/webpack.dev.js: -------------------------------------------------------------------------------- 1 | const merge = require("webpack-merge"); 2 | const common = require("./webpack.common.js"); 3 | 4 | module.exports = merge(common, { 5 | mode: "development" 6 | }); 7 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | autoprefixer: { 4 | cascade: false, 5 | flexbox: false 6 | }, 7 | ["css-mqpacker"]: { 8 | sort: true 9 | }, 10 | cssnano: { zindex: false } 11 | } 12 | }; 13 | -------------------------------------------------------------------------------- /src/pug/_mixins.pug: -------------------------------------------------------------------------------- 1 | mixin link(name = "", href = "#") 2 | a(href=href)&attributes(attributes)= name 3 | 4 | mixin icon(id, path = "img/icons/svg/sprite.symbol.svg") 5 | svg(class="svg-icon" aria-hidden="true")&attributes(attributes) 6 | use(xlink:href=`${path}#${id}`) 7 | -------------------------------------------------------------------------------- /src/sass/_vars.scss: -------------------------------------------------------------------------------- 1 | $color-primary: null; 2 | $color-secondary: null; 3 | $grid-breakpoints: (xs: 0, lg: 992px, xl: 1200px); 4 | $grid-gutter-width: 30px; 5 | $container-max-widths: (lg: 960px, xl: 1140px); 6 | $base-font-family: sans-serif; 7 | $base-bg-color: #fff; 8 | $default-transition-time: 0.4s; 9 | -------------------------------------------------------------------------------- /src/sass/modules/_container.scss: -------------------------------------------------------------------------------- 1 | .container { 2 | width: 100%; 3 | padding: { 4 | right: $grid-gutter-width / 2; 5 | left: $grid-gutter-width / 2; 6 | } 7 | margin: { 8 | right: auto; 9 | left: auto; 10 | } 11 | } 12 | 13 | @each $breakpoint, $container-max-width in $container-max-widths { 14 | @media (min-width: map-get($grid-breakpoints, $breakpoint)) { 15 | .container { 16 | max-width: $container-max-width; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /gulp/constants.js: -------------------------------------------------------------------------------- 1 | const globImporter = require("node-sass-glob-importer"); 2 | 3 | const PURIFY_CSS_OPTIONS = { 4 | info: true, 5 | rejected: true, 6 | minify: true 7 | }; 8 | 9 | const PURIFY_CSS_CONTENT = ["dist/js/*.js", "dist/**/*.html"]; 10 | 11 | const SASS_OPTIONS = { 12 | includePaths: ["node_modules"], 13 | importer: globImporter() 14 | }; 15 | 16 | const SASS_GLOB = "src/sass/**/*.{sass,scss}"; 17 | 18 | const SASS_OUTPUT_PATH = "dist/css"; 19 | 20 | module.exports = { 21 | PURIFY_CSS_OPTIONS, 22 | PURIFY_CSS_CONTENT, 23 | SASS_OPTIONS, 24 | SASS_GLOB, 25 | SASS_OUTPUT_PATH 26 | }; 27 | -------------------------------------------------------------------------------- /webpack/webpack.prod.js: -------------------------------------------------------------------------------- 1 | const merge = require("webpack-merge"); 2 | const common = require("./webpack.common.js"); 3 | const path = require("path"); 4 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 5 | 6 | const PATHS = { 7 | src: path.resolve(process.cwd(), "src"), 8 | dist: path.resolve(process.cwd(), "dist") 9 | }; 10 | 11 | const pages = { 12 | index: ["index"] 13 | }; 14 | 15 | module.exports = merge(common, { 16 | mode: "production", 17 | optimization: { 18 | splitChunks: { 19 | chunks: "all", 20 | minChunks: 2 21 | } 22 | }, 23 | plugins: Object.keys(pages).map(page => { 24 | return new HtmlWebpackPlugin({ 25 | filename: `${PATHS.dist}/${page}.html`, 26 | template: `${PATHS.dist}/${page}.html`, 27 | chunks: pages[page].concat(["common"]) 28 | }); 29 | }) 30 | }); 31 | -------------------------------------------------------------------------------- /src/pug/_layout.pug: -------------------------------------------------------------------------------- 1 | include _mixins 2 | 3 | block variables 4 | 5 | doctype html 6 | html(lang="en") 7 | head 8 | 9 | title= pageTitle 10 | 11 | meta(charset="utf-8") 12 | meta(name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no") 13 | meta(http-equiv="x-ua-compatible" content="ie=edge") 14 | meta(name="keywords" content) 15 | 16 | if isProduction 17 | link(rel="stylesheet" href="css/build.css") 18 | else 19 | link(rel="stylesheet" href="css/libs.css") 20 | link(rel="stylesheet" href="css/main.css") 21 | 22 | block styles 23 | 24 | body.page 25 | .page__wrapper 26 | include modules/_header 27 | 28 | main.page__content 29 | block content 30 | 31 | include modules/_footer 32 | 33 | block popups 34 | 35 | if !isProduction 36 | block scripts 37 | -------------------------------------------------------------------------------- /gulp/utils.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | const path = require("path"); 3 | 4 | function requireUncached(module) { 5 | delete require.cache[require.resolve(module)]; 6 | return require(module); 7 | } 8 | 9 | function readFilesToObject(dirname, obj) { 10 | let files = fs.readdirSync(dirname); 11 | 12 | files = files.filter(fileName => /\.js(on)?$/.test(fileName)); 13 | 14 | for (let file of files) { 15 | const dividedString = file.split("."); 16 | const fileExtension = dividedString[1]; 17 | const fileName = dividedString[0]; 18 | 19 | switch (fileExtension) { 20 | case "js": 21 | obj[fileName] = requireUncached(path.resolve(dirname + file)); 22 | break; 23 | case "json": 24 | obj[fileName] = JSON.parse(fs.readFileSync(dirname + file, "utf8")); 25 | } 26 | } 27 | } 28 | 29 | module.exports = { 30 | readFilesToObject 31 | }; 32 | -------------------------------------------------------------------------------- /src/sass/_base.scss: -------------------------------------------------------------------------------- 1 | *, 2 | ::after, 3 | ::before { 4 | box-sizing: inherit; 5 | } 6 | 7 | html { 8 | box-sizing: border-box; 9 | -ms-text-size-adjust: 100%; 10 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0); 11 | -ms-overflow-style: scrollbar; 12 | } 13 | 14 | body { 15 | font-family: $base-font-family; 16 | background-color: $base-bg-color; 17 | -webkit-font-smoothing: antialiased; 18 | display: flex; 19 | flex-direction: column; 20 | min-height: 100vh; 21 | } 22 | 23 | .svg-icon { 24 | display: inline-block; 25 | vertical-align: middle; 26 | stroke-width: 0; 27 | stroke: currentColor; 28 | fill: currentColor; 29 | } 30 | 31 | a, 32 | button { 33 | transition: color $default-transition-time, background-color $default-transition-time, border-color $default-transition-time, box-shadow $default-transition-time; 34 | } 35 | 36 | p { 37 | margin-top: 0; 38 | } 39 | 40 | a { 41 | text-decoration: none; 42 | } 43 | 44 | img { 45 | max-width: 100%; 46 | vertical-align: middle; 47 | } 48 | -------------------------------------------------------------------------------- /webpack/webpack.common.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | const PATHS = { 4 | src: path.resolve(process.cwd(), "src"), 5 | dist: path.resolve(process.cwd(), "dist") 6 | }; 7 | 8 | module.exports = { 9 | entry: { 10 | common: `${PATHS.src}/js/common`, 11 | index: `${PATHS.src}/js/index` 12 | }, 13 | output: { 14 | path: `${PATHS.dist}`, 15 | filename: "js/[name].js", 16 | chunkFilename: "js/[name].bundle.js" 17 | }, 18 | module: { 19 | rules: [ 20 | { 21 | test: /\.js$/, 22 | include: PATHS.src, 23 | exclude: /node_modules/, 24 | use: { 25 | loader: "babel-loader" 26 | } 27 | }, 28 | { 29 | test: /\.css$/, 30 | use: ["style-loader", "css-loader"] 31 | }, 32 | { 33 | test: /\.scss$/, 34 | use: ["style-loader", "css-loader", "sass-loader"] 35 | }, 36 | { 37 | test: /\.(png|jpg|gif|svg)$/, 38 | use: [ 39 | { 40 | loader: "file-loader", 41 | options: { 42 | name: "[name].[ext]", 43 | outputPath: "img/" 44 | } 45 | } 46 | ] 47 | } 48 | ] 49 | } 50 | }; 51 | -------------------------------------------------------------------------------- /.stylelintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "processors": ["stylelint-processor-html"], 3 | "extends": ["stylelint-config-standard"], 4 | "plugins": ["stylelint-scss"], 5 | "rules": { 6 | "at-rule-empty-line-before": [ 7 | "always", 8 | { 9 | "except": ["blockless-after-same-name-blockless", "first-nested"], 10 | "ignore": ["after-comment"], 11 | "ignoreAtRules": ["else"] 12 | } 13 | ], 14 | "block-closing-brace-newline-after": [ 15 | "always", 16 | { 17 | "ignoreAtRules": ["if", "else"] 18 | } 19 | ], 20 | "shorthand-property-no-redundant-values": true, 21 | "declaration-block-no-redundant-longhand-properties": true, 22 | "declaration-no-important": true, 23 | "at-rule-semicolon-space-before": "never", 24 | "font-family-name-quotes": "always-where-required", 25 | "string-quotes": "double", 26 | "value-keyword-case": "lower", 27 | "selector-attribute-quotes": "always", 28 | "at-rule-no-unknown": null, 29 | "scss/at-rule-no-unknown": true, 30 | "declaration-empty-line-before": "never", 31 | "scss/operator-no-unspaced": true, 32 | "scss/declaration-nested-properties": [ 33 | "always", 34 | { 35 | "except": ["only-of-namespace"] 36 | } 37 | ], 38 | "scss/double-slash-comment-empty-line-before": [ 39 | "always", 40 | { 41 | "except": ["first-nested"], 42 | "ignore": ["between-comments", "stylelint-commands"] 43 | } 44 | ], 45 | "scss/double-slash-comment-whitespace-inside": "always", 46 | "scss/dollar-variable-colon-space-after": "always", 47 | "scss/dollar-variable-colon-space-before": "never", 48 | "scss/dollar-variable-empty-line-before": [ 49 | "always", 50 | { 51 | "except": ["first-nested", "after-comment", "after-dollar-variable"] 52 | } 53 | ], 54 | "scss/dollar-variable-no-missing-interpolation": true, 55 | "scss/at-mixin-parentheses-space-before": "never", 56 | "scss/at-import-no-partial-leading-underscore": true, 57 | "scss/at-function-parentheses-space-before": "never", 58 | "scss/at-else-if-parentheses-space-before": "never", 59 | "scss/selector-no-redundant-nesting-selector": true, 60 | "scss/operator-no-newline-after": true, 61 | "scss/operator-no-newline-before": true, 62 | "scss/declaration-nested-properties-no-divided-groups": true, 63 | "scss/dollar-variable-colon-newline-after": "always-multi-line", 64 | "scss/at-if-closing-brace-space-after": "always-intermediate", 65 | "no-empty-source": null, 66 | "declaration-colon-newline-after": null 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "brave-new-world", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "gulpfile.js", 6 | "dependencies": { 7 | "normalize.css": "^8.0.1", 8 | "svg4everybody": "^2.1.9" 9 | }, 10 | "devDependencies": { 11 | "@babel/core": "^7.2.2", 12 | "@babel/plugin-transform-classes": "^7.2.2", 13 | "@babel/preset-env": "^7.2.3", 14 | "autoprefixer": "^8.6.5", 15 | "babel-loader": "^8.0.5", 16 | "browser-sync": "^2.24.7", 17 | "css-loader": "^1.0.1", 18 | "css-mqpacker": "^6.0.2", 19 | "cssnano": "^3.10.0", 20 | "del": "^3.0.0", 21 | "file-loader": "^2.0.0", 22 | "gulp": "^4.0.0", 23 | "gulp-clean-css": "^4.0.0", 24 | "gulp-concat-css": "^3.1.0", 25 | "gulp-image-resize": "^0.13.0", 26 | "gulp-imagemin": "^4.1.0", 27 | "gulp-load-plugins": "^1.5.0", 28 | "gulp-notify": "^3.2.0", 29 | "gulp-plumber": "^1.2.1", 30 | "gulp-postcss": "^7.0.1", 31 | "gulp-pug": "^4.0.1", 32 | "gulp-purifycss": "^0.2.0", 33 | "gulp-rename": "^1.4.0", 34 | "gulp-sass": "^4.0.1", 35 | "gulp-sourcemaps": "^2.6.4", 36 | "gulp-svg-sprite": "^1.4.0", 37 | "gulp-uncss": "^1.0.6", 38 | "gulp-util": "^3.0.8", 39 | "html-webpack-plugin": "^4.0.0-beta.5", 40 | "husky": "^2.2.0", 41 | "lint-staged": "^8.1.6", 42 | "node-sass-glob-importer": "^5.3.0", 43 | "postcss-load-config": "^2.0.0", 44 | "postcss-loader": "^3.0.0", 45 | "prettier": "^1.17.0", 46 | "sass-loader": "^7.1.0", 47 | "style-loader": "^0.23.1", 48 | "stylelint": "^9.9.0", 49 | "stylelint-config-standard": "^18.2.0", 50 | "stylelint-processor-html": "^1.0.0", 51 | "stylelint-scss": "^3.4.4", 52 | "vinyl-ftp": "^0.6.1", 53 | "webpack": "^4.28.3", 54 | "webpack-cli": "^3.2.0", 55 | "webpack-merge": "^4.1.5", 56 | "webpack-stream": "^5.2.1", 57 | "yargs": "^12.0.5" 58 | }, 59 | "scripts": { 60 | "build:scripts": "webpack --config webpack/webpack.prod.js", 61 | "stylelint": "stylelint ./**/*.{scss,vue} --syntax scss", 62 | "prettier": "prettier --write ./**/*.{js,vue}", 63 | "build": "gulp build && npm run build:scripts && gulp build:css --fix", 64 | "deploy": "npm run build && gulp deploy", 65 | "webpack:stats": "webpack --profile --json > webpack-stats.json" 66 | }, 67 | "author": "", 68 | "license": "ISC", 69 | "husky": { 70 | "hooks": { 71 | "pre-commit": "lint-staged" 72 | } 73 | }, 74 | "lint-staged": { 75 | "*.{js,css,json,md}": [ 76 | "prettier --write", 77 | "git add" 78 | ], 79 | "*.css": [ 80 | "stylelint", 81 | "git add" 82 | ] 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/sass/_mixins.scss: -------------------------------------------------------------------------------- 1 | @mixin md() { 2 | @media (min-width: map-get($map: $grid-breakpoints, $key: md)) { 3 | @content; 4 | } 5 | } 6 | 7 | @mixin lg() { 8 | @media (min-width: map-get($map: $grid-breakpoints, $key: lg)) { 9 | @content; 10 | } 11 | } 12 | 13 | @mixin xl() { 14 | @media (min-width: map-get($map: $grid-breakpoints, $key: xl)) { 15 | @content; 16 | } 17 | } 18 | 19 | @mixin from-xs-to-lg() { 20 | @media (min-width: map-get($map: $grid-breakpoints, $key: xs)) and (max-width: map-get($map: $grid-breakpoints, $key: lg) - 0.02px) { 21 | @content; 22 | } 23 | } 24 | 25 | @mixin from-lg-to-xl() { 26 | @media (min-width: map-get($map: $grid-breakpoints, $key: lg)) and (max-width: map-get($map: $grid-breakpoints, $key: xl) - 0.02px) { 27 | @content; 28 | } 29 | } 30 | 31 | @mixin input-placeholder { 32 | &::placeholder { 33 | @content; 34 | } 35 | } 36 | 37 | @mixin center($position) { 38 | position: absolute; 39 | 40 | @if ($position == "vertical") { 41 | top: 50%; 42 | transform: translateY(-50%); 43 | } @else if($position == "horizontal") { 44 | left: 50%; 45 | transform: translateX(-50%); 46 | } @else if($position == "both") { 47 | top: 50%; 48 | left: 50%; 49 | transform: translate(-50%, -50%); 50 | } 51 | } 52 | 53 | @function rem($size, $base: 16px) { 54 | $remSize: $size / $base; 55 | 56 | @return #{$remSize}rem; 57 | } 58 | 59 | @function em($size, $base: 16px) { 60 | $emSize: $size / $base; 61 | 62 | @return #{$emSize}em; 63 | } 64 | 65 | @function str-replace($string, $search, $replace: "") { 66 | $index: str-index($string, $search); 67 | 68 | @if $index { 69 | @return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace); 70 | } 71 | 72 | @return $string; 73 | } 74 | 75 | @mixin font-face($name, $path, $weight: null, $style: null, $extensions: eot woff2 woff ttf svg) { 76 | $src: null; 77 | $mods: (eot: "?#iefix", svg: "#" + str-replace($name, " ", "_")); 78 | $formats: (otf: "opentype", ttf: "truetype"); 79 | 80 | @each $ext in $extensions { 81 | $mod: if(map-has-key($mods, $ext), $ext + map-get($mods, $ext), $ext); 82 | $format: if(map-has-key($formats, $ext), map-get($formats, $ext), $ext); 83 | $src: append($src, url(quote($path + "." + $mod)) format(quote($format)), comma); 84 | } 85 | 86 | @font-face { 87 | font: { 88 | family: quote($name); 89 | style: $style; 90 | weight: $weight; 91 | } 92 | src: $src; 93 | } 94 | } 95 | 96 | @mixin box($width, $height: $width) { 97 | width: $width; 98 | height: $height; 99 | } 100 | 101 | @mixin position($position, $top: null, $right: null, $bottom: null, $left: null) { 102 | position: $position; 103 | top: $top; 104 | right: $right; 105 | bottom: $bottom; 106 | left: $left; 107 | } 108 | 109 | @mixin absolute($args...) { 110 | @include position(absolute, $args...); 111 | } 112 | 113 | @mixin relative($args...) { 114 | @include position(relative, $args...); 115 | } 116 | 117 | @mixin fixed($args...) { 118 | @include position(fixed, $args...); 119 | } 120 | 121 | @mixin sticky($args...) { 122 | @include position(sticky, $args...); 123 | } 124 | 125 | @mixin reset-list() { 126 | padding-left: 0; 127 | margin: { 128 | top: 0; 129 | bottom: 0; 130 | } 131 | list-style: none; 132 | } 133 | 134 | @mixin reset-button() { 135 | background-color: transparent; 136 | border-width: 0; 137 | } 138 | 139 | @mixin box-shadow($color) { 140 | box-shadow: $default-box-shadow rgba($color, 0.25); 141 | } 142 | 143 | @mixin row() { 144 | margin: { 145 | right: -$grid-gutter-width / 2; 146 | left: -$grid-gutter-width / 2; 147 | } 148 | } 149 | 150 | @mixin col() { 151 | padding: { 152 | right: $grid-gutter-width / 2; 153 | left: $grid-gutter-width / 2; 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const gulp = require("gulp"), 4 | p = require("gulp-load-plugins")(), 5 | del = require("del"), 6 | bs = require("browser-sync").create(), 7 | fs = require("fs"), 8 | argv = require("yargs").argv, 9 | ftp = require("vinyl-ftp"), 10 | webpack = require("webpack-stream"), 11 | compiler = require("webpack"), 12 | utils = require("./gulp/utils"), 13 | constants = require("./gulp/constants"); 14 | 15 | let isProduction; 16 | 17 | console.log(p); 18 | 19 | // Remove build directory 20 | gulp.task("clean", () => { 21 | return del(["dist"]); 22 | }); 23 | 24 | gulp.task("clean:css", () => { 25 | return del(["dist/css/*.css", "!dist/css/build.css"]); 26 | }); 27 | 28 | // Pug 29 | gulp.task("pug", () => { 30 | const dataFiles = {}; 31 | utils.readFilesToObject("src/pug/data/", dataFiles); 32 | 33 | return gulp 34 | .src("src/pug/**/!(_)*.pug") 35 | .pipe( 36 | p.pug({ 37 | locals: { 38 | isProduction, 39 | ...dataFiles 40 | } 41 | }) 42 | ) 43 | .on( 44 | "error", 45 | p.notify.onError(error => { 46 | return { 47 | title: "Pug", 48 | message: error.message 49 | }; 50 | }) 51 | ) 52 | .pipe(gulp.dest("dist")) 53 | .on("end", bs.reload); 54 | }); 55 | 56 | gulp.task("styles:dev", () => { 57 | return gulp 58 | .src(constants.SASS_GLOB) 59 | .pipe(p.sourcemaps.init()) 60 | .pipe(p.plumber()) 61 | .pipe(p.sass(constants.SASS_OPTIONS).on("error", p.sass.logError)) 62 | .pipe(p.sourcemaps.write(".")) 63 | .pipe(gulp.dest(constants.SASS_OUTPUT_PATH)) 64 | .pipe(bs.stream()); 65 | }); 66 | 67 | gulp.task("styles:build", () => { 68 | return gulp 69 | .src(constants.SASS_GLOB) 70 | .pipe(p.sass(constants.SASS_OPTIONS).on("error", p.sass.logError)) 71 | .pipe(p.postcss()) 72 | .pipe(gulp.dest(constants.SASS_OUTPUT_PATH)); 73 | }); 74 | 75 | gulp.task("purifycss:libs", () => { 76 | return gulp 77 | .src(["dist/css/*.css", "!dist/css/main.css"]) 78 | .pipe( 79 | p.purifycss(constants.PURIFY_CSS_CONTENT, constants.PURIFY_CSS_OPTIONS) 80 | ) 81 | .pipe( 82 | p.uncss({ 83 | html: ["dist/**/*.html"], 84 | ignore: [] 85 | }) 86 | ) 87 | .pipe(gulp.dest(constants.SASS_OUTPUT_PATH)); 88 | }); 89 | 90 | gulp.task("purifycss:source", () => { 91 | return gulp 92 | .src("dist/css/main.css") 93 | .pipe( 94 | p.purifycss(constants.PURIFY_CSS_CONTENT, constants.PURIFY_CSS_OPTIONS) 95 | ) 96 | .pipe(gulp.dest(constants.SASS_OUTPUT_PATH)); 97 | }); 98 | 99 | gulp.task("concat:css", function() { 100 | return gulp 101 | .src("dist/css/*.css") 102 | .pipe(p.concatCss("dist/css/build.css", { rebaseUrls: false })) 103 | .pipe(p.cleanCss()) 104 | .pipe(gulp.dest("./")); 105 | }); 106 | 107 | gulp.task("scripts", () => { 108 | return gulp 109 | .src("src/js/**/*.js") 110 | .pipe( 111 | webpack(require("./webpack/webpack.dev.js"), compiler, function( 112 | err, 113 | stats 114 | ) { 115 | /* Use stats to do more things if needed */ 116 | }) 117 | ) 118 | .pipe(gulp.dest("dist")); 119 | }); 120 | 121 | gulp.task("watch", () => { 122 | gulp.watch("src/pug/**/*", gulp.series("pug")); 123 | 124 | gulp.watch("src/sass/**/*.{sass,scss}", gulp.series("styles:dev")); 125 | 126 | gulp.watch("src/fonts/**/*.*", gulp.series("fonts")); 127 | 128 | gulp.watch("src/img/**/*.*", gulp.series("img:dev")); 129 | 130 | gulp.watch("src/img/icons/svg/*.svg", gulp.series("svgSprite")); 131 | 132 | gulp.watch("src/js/**/*.js", gulp.series("scripts")); 133 | }); 134 | 135 | gulp.task("fonts", () => { 136 | return gulp.src("src/fonts/**/*.*").pipe(gulp.dest("dist/fonts")); 137 | }); 138 | 139 | gulp.task("img:dev", () => { 140 | return gulp.src("src/img/**/*.*").pipe(gulp.dest("dist/img")); 141 | }); 142 | 143 | gulp.task("img:build", () => { 144 | return gulp 145 | .src(["src/img/**/*.{jpg,png,svg}", "!src/img/icons/**/*.svg"]) 146 | .pipe( 147 | p.imagemin([ 148 | p.imagemin.svgo({ 149 | plugins: [ 150 | { 151 | inlineStyles: { 152 | onlyMatchedOnce: false 153 | } 154 | }, 155 | { removeStyleElement: true }, 156 | { 157 | removeUnknownsAndDefaults: { 158 | keepDataAttrs: false 159 | } 160 | }, 161 | { 162 | removeAttrs: { 163 | attrs: ["class"] 164 | } 165 | }, 166 | { 167 | cleanupListOfValues: { 168 | floatPrecision: 2 169 | } 170 | }, 171 | { removeTitle: false } 172 | ] 173 | }) 174 | ]) 175 | ) 176 | .pipe(gulp.dest("dist/img")); 177 | }); 178 | 179 | gulp.task("crop", () => { 180 | return gulp 181 | .src("src/img/crop/*.*") 182 | .pipe( 183 | p.imageResize({ 184 | width: argv.width, 185 | height: argv.height, 186 | crop: Boolean(argv.width && argv.height), 187 | upscale: true, 188 | noProfile: true 189 | }) 190 | ) 191 | .pipe(p.rename({ suffix: `_${argv.width}` })) 192 | .pipe(gulp.dest("src/img/cropped")); 193 | }); 194 | 195 | // Sprites 196 | gulp.task("svgSprite", () => { 197 | let config = { 198 | log: "verbose", 199 | shape: { 200 | id: { 201 | separator: "--" 202 | }, 203 | transform: [ 204 | { 205 | svgo: { 206 | plugins: [ 207 | { 208 | cleanupListOfValues: { 209 | floatPrecision: 2 210 | } 211 | }, 212 | { removeXMLNS: true }, 213 | { removeTitle: false } 214 | ] 215 | } 216 | } 217 | ] 218 | }, 219 | mode: { 220 | symbol: { 221 | dest: ".", 222 | sprite: "sprite.symbol.svg" 223 | } 224 | } 225 | }; 226 | 227 | return gulp 228 | .src("**/*.svg", { cwd: "src/img/icons/svg" }) 229 | .pipe(p.svgSprite(config)) 230 | .pipe(gulp.dest("dist/img/icons/svg")); 231 | }); 232 | 233 | gulp.task("deploy", () => { 234 | const ftpCredentials = JSON.parse(fs.readFileSync("./ftp.json")); 235 | const { host, user, password, folder } = ftpCredentials; 236 | 237 | let conn = ftp.create({ 238 | host, 239 | user, 240 | password, 241 | parallel: 10, 242 | log: p.util 243 | }); 244 | 245 | const globs = ["dist/**/*"]; 246 | 247 | return gulp 248 | .src(globs, { base: "./dist", buffer: false }) 249 | .pipe(conn.newer(folder)) 250 | .pipe(conn.dest(folder)); 251 | }); 252 | 253 | gulp.task("serve", function() { 254 | bs.init({ 255 | server: { 256 | baseDir: "dist" 257 | } 258 | }); 259 | }); 260 | 261 | gulp.task( 262 | "build:css", 263 | gulp.series("purifycss:libs", "purifycss:source", "concat:css", "clean:css") 264 | ); 265 | 266 | gulp.task( 267 | "dev", 268 | gulp.series( 269 | "clean", 270 | gulp.parallel( 271 | "styles:dev", 272 | "pug", 273 | "fonts", 274 | "img:dev", 275 | "svgSprite", 276 | "scripts" 277 | ) 278 | ) 279 | ); 280 | 281 | gulp.task( 282 | "build", 283 | gulp.series( 284 | "clean", 285 | () => 286 | new Promise(resolve => { 287 | isProduction = true; 288 | resolve(); 289 | }), 290 | gulp.parallel("styles:build", "pug", "fonts", "img:build", "svgSprite") 291 | ) 292 | ); 293 | 294 | gulp.task("default", gulp.series("dev", gulp.parallel("watch", "serve"))); 295 | --------------------------------------------------------------------------------