├── .babelrc.js ├── .browserslistrc ├── .codeclimate.yml ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .huskyrc ├── .netlify └── state.json ├── .nvmrc ├── .stylelintignore ├── .stylelintrc ├── .vscode └── settings.json ├── LICENSE ├── README.md ├── gulpfile.babel.js ├── package.json ├── postcss.config.js ├── site-config.json ├── source ├── components │ ├── buttons │ │ ├── button.js │ │ ├── button.scss │ │ └── buttons.pug │ └── hero │ │ ├── hero.js │ │ ├── hero.pug │ │ └── hero.scss ├── images │ ├── icon-white.png │ ├── icon-white.svg │ ├── icon.png │ ├── icon.sketch │ └── share.jpg ├── index.js ├── index.pug ├── layouts │ ├── _favicons.pug │ ├── _head.pug │ ├── _metas.pug │ ├── _scripts.pug │ └── default.pug ├── static │ ├── _redirects │ ├── humans.txt │ └── robots.txt └── styles │ ├── _base.scss │ ├── _mixins.scss │ ├── _vars.scss │ └── main.scss ├── tasks ├── build.js ├── config │ ├── base.js │ ├── index.js │ ├── paths.js │ ├── plugins.js │ └── webpack.js ├── favicons.js ├── index.js ├── static.js └── watch.js └── yarn.lock /.babelrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@babel/preset-env' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 1 version 3 | maintained node versions 4 | not dead 5 | -------------------------------------------------------------------------------- /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | 3 | plugins: 4 | eslint: 5 | enabled: true 6 | channel: 'eslint-5' 7 | config: 8 | config: .eslintrc.js 9 | 10 | checks: 11 | method-complexity: 12 | enabled: false 13 | method-lines: 14 | config: 15 | threshold: 150 16 | similar-code: 17 | enabled: false 18 | identical-code: 19 | enabled: false 20 | 21 | ratings: 22 | paths: 23 | - '**.js' 24 | - '**.scss' 25 | 26 | exclude_paths: 27 | - .vscode/**/* 28 | - .netlify/**/* 29 | - dist/**/* 30 | - source/img/**/* 31 | - source/static/**/* 32 | - source/scss/clean-admin/**/* 33 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | # The JSON files contain newlines inconsistently 13 | [*.json] 14 | insert_final_newline = ignore 15 | 16 | # Minified JavaScript files shouldn't be changed 17 | [**.min.js] 18 | indent_style = ignore 19 | insert_final_newline = ignore 20 | 21 | [*.md] 22 | trim_trailing_whitespace = false 23 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | dist 2 | __src 3 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: 'standard', 3 | env: { 4 | browser: true, 5 | es6: true, 6 | jquery: true 7 | }, 8 | globals: { 9 | "$": true, 10 | "jQuery": true, 11 | "fetch": true, 12 | "window": true, 13 | "document": true 14 | }, 15 | rules: { 16 | 'quote-props': 'off', 17 | 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off', 18 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off' 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | dist 61 | __src 62 | source/components/**/*.json 63 | -------------------------------------------------------------------------------- /.huskyrc: -------------------------------------------------------------------------------- 1 | { 2 | "hooks": { 3 | "pre-commit": "npm run lint" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.netlify/state.json: -------------------------------------------------------------------------------- 1 | { 2 | "siteId": "59489b42-daeb-4c07-af4a-158aae7ff899" 3 | } -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 10 -------------------------------------------------------------------------------- /.stylelintignore: -------------------------------------------------------------------------------- 1 | **/*.css 2 | -------------------------------------------------------------------------------- /.stylelintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "stylelint-config-sass-guidelines", 3 | "rules": { 4 | "indentation": 2, 5 | "max-nesting-depth": 3, 6 | "number-leading-zero": null, 7 | "at-rule-empty-line-before": null, 8 | "no-descending-specificity": null, 9 | "scss/dollar-variable-pattern": null 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "eslint.autoFixOnSave": true, 3 | "eslint.alwaysShowStatus": true, 4 | "eslint.enable": true, 5 | "stylelint.enable": true, 6 | "css.validate": false, 7 | "scss.validate": true, 8 | "files.exclude": { 9 | "**/node_modules": false 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 OneDev studio 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [Starter Kit](https://starter-kit.nandomoreira.dev/) 2 | 3 | [![Maintainability](https://api.codeclimate.com/v1/badges/e98eec03de678dcdb610/maintainability)](https://codeclimate.com/github/onedevstudio/starter-kit/maintainability) ![GitHub](https://img.shields.io/github/license/onedevstudio/starter-kit.svg) ![GitHub repo size](https://img.shields.io/github/repo-size/onedevstudio/starter-kit.svg) ![GitHub package.json version](https://img.shields.io/github/package-json/v/onedevstudio/starter-kit.svg) [![Netlify Status](https://api.netlify.com/api/v1/badges/59489b42-daeb-4c07-af4a-158aae7ff899/deploy-status)](https://app.netlify.com/sites/starter-kit/deploys) 4 | 5 | > A simple and powerful Starter Kit made with Webpack, Gulp 4, Pug and SASS 6 | 7 | ## Table of Contents 8 | 9 | - [Installation](#installation) 10 | - [Support](#support) 11 | - [Contributing](#contributing) 12 | - [Tasks](#tasks) 13 | - [History](#history) 14 | - [License](#license) 15 | 16 | ## Installation 17 | 18 | ```bash 19 | git clone https://github.com/onedevstudio/starter-kit.git your-project 20 | cd your-project/ && rm -rf .git 21 | yarn install # or npm install 22 | yarn dev # or npm run dev 23 | ``` 24 | 25 | ## Support 26 | 27 | Please [open an issue](../../issues/new) for support. 28 | 29 | ## Contributing 30 | 31 | Please contribute using [Github Flow](https://guides.github.com/introduction/flow/). Create a branch, add commits, and [open a pull request](../../compare?expand=1). 32 | Contributing 33 | 34 | 1. Fork it! 35 | 2. Create your feature branch: git checkout -b my-new-feature 36 | 3. Commit your changes: git commit -m 'Add some feature' 37 | 4. Push to the branch: git push origin my-new-feature 38 | 5. Submit a pull request :D 39 | 40 | ## Tasks 41 | 42 | **Gulp tasks** 43 | 44 | - `gulp` ~> Build and watch files 45 | - `gulp watch` ~> Watch js files 46 | - `gulp server` ~> Watch js files and start browser sync server 47 | - `gulp copyFiles` ~> Copy static files 48 | - `gulp favicons` ~> Generate all favicons 49 | - `gulp build` ~> Build all files 50 | 51 | **NPM scripts** 52 | 53 | - `npm run start` ~> Starts the task `gulp server` in env production 54 | - `npm run prod` ~> Starts the tasks `npm run lint` and `npm run build` 55 | - `npm run build` ~> Starts the tasks `gulp build` in env production 56 | - `npm run dev` ~> Starts the tasks `gulp` in env development 57 | - `npm run deploy` ~> Starts the tasks `npm run prod` and run the command `netlify deploy --prod` 58 | - `npm run eslint` ~> Run the command `eslint .` 59 | - `npm run eslint:fix` ~> Run the task `npm run eslint --fix` 60 | - `npm run stylelint` ~> Run the command `stylelint "**/*.scss"` 61 | - `npm run stylelint:fix` ~> Run the task `npm run stylelint --fix` 62 | - `npm run lint` ~> Starts the tasks `npm run eslint` and `npm run stylelint` 63 | - `npm run pre-commit` ~> Start the task `npm run lint` 64 | 65 | ## History 66 | 67 | See [Releases](../../releases) for detailed changelog. 68 | 69 | ## Author 70 | 71 | | [![twitter/oseunando](https://avatars6.githubusercontent.com/u/1318271?v=4&s=120)](http://twitter.com/oseunando "Follow @oseunando on Twitter") | 72 | | ----------------------------------------------------------------------------------------------------------------------------------------------- | 73 | | [Fernando Moreira](http://twitter.com/oseunando) | 74 | 75 | ## License 76 | 77 | ``` 78 | WWWWWW||WWWWWW 79 | W W W||W W W 80 | || 81 | ( OO )__________ 82 | / | \ 83 | /o o| MIT \ 84 | \___/||_||__||_|| * 85 | || || || || 86 | _||_|| _||_|| 87 | (__|__|(__|__| 88 | ``` 89 | 90 | Code is under [MIT License](/LICENSE) - © Fernando Moreira 91 | 92 | ## Buy me a coffee? 93 | 94 | It will encourage me to keep it going, fix whatever bugs you find and spend time making it better :D 95 | 96 | 97 | Buy me a coffee? - https://www.paypal.me/nandomoreira/5 98 | 99 | -------------------------------------------------------------------------------- /gulpfile.babel.js: -------------------------------------------------------------------------------- 1 | import defaultTask from './tasks' 2 | 3 | export * from './tasks' // eslint-disable-line 4 | 5 | export default defaultTask 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "starter-kit", 3 | "version": "2.4.0", 4 | "title": "Starter Kit", 5 | "description": "A simple and powerful Starter Kit made with Webpack, Gulp 4, Pug and SASS", 6 | "homepage": "https://starter-kit.nandomoreira.dev", 7 | "main": "gulpfile.babel.js", 8 | "scripts": { 9 | "start": "NODE_ENV=production gulp server", 10 | "prod": "npm run lint && npm run build", 11 | "build": "NODE_ENV=production gulp build", 12 | "dev": "NODE_ENV=development gulp", 13 | "deploy": "npm run prod && npm run deploy:netlify", 14 | "deploy:netlify": "netlify deploy --prod --message \"Deploy with netlify command line\"", 15 | "eslint": "eslint .", 16 | "eslint:fix": "npm run eslint --fix", 17 | "stylelint": "stylelint \"./source/styles/**/*.scss\"", 18 | "stylelint:fix": "npm run stylelint --fix", 19 | "lint": "npm run eslint && npm run stylelint", 20 | "pre-commit": "npm run lint", 21 | "test": "echo 'no has test! lol'" 22 | }, 23 | "repository": { 24 | "type": "git", 25 | "url": "https://github.com/onedevstudio/starter-kit" 26 | }, 27 | "keywords": [ 28 | "starter-kit", 29 | "starter", 30 | "kit", 31 | "babel", 32 | "es6", 33 | "stylus", 34 | "gulp", 35 | "gulpjs" 36 | ], 37 | "author": { 38 | "name": "Fernando Moreira", 39 | "email": "nandomoreira.me@gmail.com", 40 | "site": "https://nandomoreira.dev", 41 | "twitter": "oseunando" 42 | }, 43 | "license": "MIT", 44 | "bugs": { 45 | "url": "https://github.com/onedevstudio/starter-kit/issues" 46 | }, 47 | "engines": { 48 | "node": ">=10" 49 | }, 50 | "dependencies": {}, 51 | "devDependencies": { 52 | "@babel/cli": "^7.5.5", 53 | "@babel/core": "^7.5.5", 54 | "@babel/plugin-proposal-object-rest-spread": "^7.5.5", 55 | "@babel/preset-env": "^7.5.5", 56 | "@babel/register": "^7.5.5", 57 | "autoprefixer": "^9.6.1", 58 | "babel-loader": "^8.0.6", 59 | "browser-sync": "^2.26.7", 60 | "clean-webpack-plugin": "^3.0.0", 61 | "css-loader": "^3.2.0", 62 | "cssnano": "^4.1.10", 63 | "dotenv": "^8.1.0", 64 | "eslint": "^6.2.2", 65 | "eslint-config-standard": "^13.0.1", 66 | "eslint-plugin-import": "^2.18.2", 67 | "eslint-plugin-node": "^9.1.0", 68 | "eslint-plugin-promise": "^4.2.1", 69 | "eslint-plugin-standard": "^4.0.1", 70 | "favicons": "^5.4.1", 71 | "file-loader": "^4.2.0", 72 | "gulp": "^4.0.2", 73 | "gulp-size": "^3.0.0", 74 | "gulp-util": "^3.0.8", 75 | "html-webpack-plugin": "^3.2.0", 76 | "husky": "^3.0.4", 77 | "lost": "^8.3.1", 78 | "mini-css-extract-plugin": "^0.8.0", 79 | "netlify-cli": "^2.12.0", 80 | "node-sass": "^4.12.0", 81 | "offline-plugin": "^5.0.7", 82 | "postcss-font-magician": "^2.2.2", 83 | "postcss-loader": "^3.0.0", 84 | "postcss-modules": "^1.4.1", 85 | "pug": "^2.0.4", 86 | "pug-loader": "^2.4.0", 87 | "rucksack-css": "^1.0.2", 88 | "sass-loader": "^7.3.1", 89 | "style-loader": "^0.23.1", 90 | "stylelint": "^10.1.0", 91 | "stylelint-config-sass-guidelines": "^6.0.0", 92 | "stylelint-config-standard": "^18.3.0", 93 | "webpack": "^4.39.2", 94 | "webpack-dev-middleware": "^3.7.0", 95 | "webpack-hot-middleware": "^2.25.0" 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const { 3 | dirname, 4 | basename, 5 | resolve 6 | } = require('path') 7 | 8 | module.exports = { 9 | plugins: { 10 | 'rucksack-css': {}, 11 | 'lost': {}, 12 | 'postcss-font-magician': {}, 13 | 'autoprefixer': {}, 14 | 'cssnano': { 15 | add: true 16 | }, 17 | 'postcss-modules': { 18 | getJSON (cssFileName, json) { 19 | const isComponent = /components/.test(dirname(cssFileName)) 20 | 21 | if (isComponent) { 22 | const cssName = basename(`${cssFileName}`) 23 | const jsonFileName = resolve(`${dirname(cssFileName)}/${cssName.split('.')[0]}-css.json`) 24 | fs.writeFileSync(jsonFileName, JSON.stringify(json)) 25 | } 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /site-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "lang": "en-US", 3 | "locale": "en_US", 4 | "icon": "images/icon.png", 5 | "theme_color": "#0b7ff5", 6 | "ga": "UA-125092358-6" 7 | } 8 | -------------------------------------------------------------------------------- /source/components/buttons/button.js: -------------------------------------------------------------------------------- 1 | import './button.scss' 2 | -------------------------------------------------------------------------------- /source/components/buttons/button.scss: -------------------------------------------------------------------------------- 1 | @import '../../styles/vars'; 2 | 3 | .button { 4 | border: 0.125rem solid transparent; 5 | border-radius: 0.1875rem /* 3/16 */; 6 | color: #fff; 7 | cursor: pointer; 8 | display: inline-block; 9 | font-size: 1rem /* 16/16 */; 10 | font-weight: 500; 11 | letter-spacing: 0.05em; 12 | line-height: 2.375rem; 13 | margin: 0.625rem /* 10/16 */; 14 | padding: 0 0.75rem /* 12/16 */; 15 | text-align: center; 16 | text-decoration: none; 17 | transition: background-color 0.1s ease-in-out, 18 | border-color 0.1s ease-in-out, 19 | color 0.1s ease-in-out, 20 | box-shadow 0.1s ease-in-out, 21 | transform 0.1s ease-in-out; 22 | white-space: nowrap; 23 | 24 | span, 25 | svg { 26 | display: inline-block; 27 | margin: 0 0.3125rem /* 5/16 */; 28 | vertical-align: middle; 29 | } 30 | 31 | &:focus, 32 | &:active, 33 | &:hover { 34 | background-color: darken($primaryColor, 20%); 35 | border-color: darken($primaryColor, 20%); 36 | color: #fff; 37 | } 38 | } 39 | 40 | .primary { 41 | background-color: darken($primaryColor, 10%); 42 | border-color: darken($primaryColor, 10%); 43 | } 44 | 45 | .secondary { 46 | background-color: transparent; 47 | border-color: darken($primaryColor, 15%); 48 | } 49 | -------------------------------------------------------------------------------- /source/components/buttons/buttons.pug: -------------------------------------------------------------------------------- 1 | - var css = require('./button-css.json'); 2 | 3 | a(class=css.button + ' ' + css.primary href=globals.repository.url target='_blank') 4 | svg.icon.icon-github(xmlns='http://www.w3.org/2000/svg', width='22', height='22', viewbox='0 0 24 24', fill='none', stroke='currentColor', stroke-width='2', stroke-linecap='round', stroke-linejoin='round') 5 | path(d='M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22') 6 | span='Github Repo' 7 | 8 | a(class=css.button + ' ' + css.secondary href=globals.repository.url + '/releases/tag/v' + globals.version target='_blank') 9 | span='Download v' + globals.version 10 | -------------------------------------------------------------------------------- /source/components/hero/hero.js: -------------------------------------------------------------------------------- 1 | import './hero.scss' 2 | -------------------------------------------------------------------------------- /source/components/hero/hero.pug: -------------------------------------------------------------------------------- 1 | - var css = require('./hero-css.json'); 2 | 3 | section(class=css.hero) 4 | div(class=css.hero__inner) 5 | span(class=css.hero__icon) 6 | img(src=require('../../images/icon-white.svg') alt=globals.title) 7 | h1(class=css.hero__title) 8 | =globals.title 9 | p(class=css.hero__description) 10 | ='{{ ' + globals.description + ' }}' 11 | div(class=css.hero__buttons) 12 | include ../buttons/buttons.pug 13 | footer(class=css.hero__footer) 14 | small 15 | ='Version: v' + globals.version + '. ' 16 | ='developed by ' 17 | a(href=globals.author.site + '?ref=' + globals.homepage target='_blank') 18 | =globals.author.name 19 | -------------------------------------------------------------------------------- /source/components/hero/hero.scss: -------------------------------------------------------------------------------- 1 | @import '../../styles/vars'; 2 | @import '../../styles/mixins'; 3 | 4 | .hero { 5 | padding: 3.75rem /* 60/16 */ 0 1.25rem /* 20/16 */; 6 | text-align: center; 7 | 8 | @include media(min-width $breakpoint-md) { 9 | align-items: center; 10 | display: flex; 11 | height: 100vh; 12 | justify-content: center; 13 | padding: 0; 14 | } 15 | 16 | &__inner { 17 | max-width: 62.5rem /* 1000/16 */; 18 | padding: 0.9375rem /* 15/16 */; 19 | } 20 | 21 | &__icon { 22 | display: block; 23 | margin: 0; 24 | 25 | img { 26 | width: 6.25rem /* 100/16 */; 27 | } 28 | } 29 | 30 | &__title { 31 | font-size: 2.625rem /* 42/16 */; 32 | margin-bottom: 0.9375rem /* 15/16 */; 33 | 34 | @include media(min-width $breakpoint-sm) { 35 | font-size: 3.875rem /* 62/16 */; 36 | } 37 | 38 | @include media(min-width $breakpoint-md) { 39 | font-size: 4.5rem /* 72/16 */; 40 | } 41 | } 42 | 43 | &__description { 44 | color: rgba($textColor, .6); 45 | font-size: 1.125rem /* 18/16 */; 46 | font-weight: 300; 47 | margin-bottom: 1.875rem /* 30/16 */; 48 | 49 | @include media(min-width $breakpoint-md) { 50 | font-size: 1.375rem /* 22/16 */; 51 | } 52 | } 53 | 54 | &__buttons { 55 | a { 56 | display: inline-block; 57 | margin-bottom: 0.3125rem /* 5/16 */; 58 | width: 100%; 59 | 60 | @include media(min-width $breakpoint-sm) { 61 | margin-bottom: 0; 62 | width: auto; 63 | } 64 | } 65 | } 66 | 67 | &__footer { 68 | margin-top: 3.75rem /* 60/16 */; 69 | text-align: center; 70 | width: 100%; 71 | 72 | @include media(min-width $breakpoint-md) { 73 | bottom: 1.875rem /* 30/16 */; 74 | left: 50%; 75 | margin-top: 0; 76 | opacity: 0.75; 77 | position: fixed; 78 | transform: translate3d(-50%, 0, 0); 79 | } 80 | 81 | small { 82 | color: rgba($textColor, .6); 83 | } 84 | 85 | a { 86 | border-bottom: 1px solid $linkColor; 87 | font-weight: 700; 88 | 89 | &:hover { 90 | text-decoration: none; 91 | } 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /source/images/icon-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onedevstudio/starter-kit/4c255707d183ab8b65ac367d5184f0130c0114f2/source/images/icon-white.png -------------------------------------------------------------------------------- /source/images/icon-white.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | icon-white 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /source/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onedevstudio/starter-kit/4c255707d183ab8b65ac367d5184f0130c0114f2/source/images/icon.png -------------------------------------------------------------------------------- /source/images/icon.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onedevstudio/starter-kit/4c255707d183ab8b65ac367d5184f0130c0114f2/source/images/icon.sketch -------------------------------------------------------------------------------- /source/images/share.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onedevstudio/starter-kit/4c255707d183ab8b65ac367d5184f0130c0114f2/source/images/share.jpg -------------------------------------------------------------------------------- /source/index.js: -------------------------------------------------------------------------------- 1 | import * as offline from 'offline-plugin/runtime' 2 | 3 | import './styles/main.scss' 4 | import './components/hero/hero.js' 5 | import './components/buttons/button.js' 6 | 7 | offline.install({ 8 | onUpdateReady: () => offline.applyUpdate() 9 | }) 10 | -------------------------------------------------------------------------------- /source/index.pug: -------------------------------------------------------------------------------- 1 | extends layouts/default.pug 2 | block content 3 | include components/hero/hero.pug 4 | -------------------------------------------------------------------------------- /source/layouts/_favicons.pug: -------------------------------------------------------------------------------- 1 | link(rel='apple-touch-icon' sizes='114x114' href=globals.homepage + globals.favicons.path + 'apple-touch-icon-114x114.png') 2 | link(rel='apple-touch-icon' sizes='120x120' href=globals.homepage + globals.favicons.path + 'apple-touch-icon-120x120.png') 3 | link(rel='apple-touch-icon' sizes='144x144' href=globals.homepage + globals.favicons.path + 'apple-touch-icon-144x144.png') 4 | link(rel='apple-touch-icon' sizes='152x152' href=globals.homepage + globals.favicons.path + 'apple-touch-icon-152x152.png') 5 | link(rel='apple-touch-icon' sizes='180x180' href=globals.homepage + globals.favicons.path + 'apple-touch-icon-180x180.png') 6 | link(rel='apple-touch-icon' sizes='57x57' href=globals.homepage + globals.favicons.path + 'apple-touch-icon-57x57.png') 7 | link(rel='apple-touch-icon' sizes='60x60' href=globals.homepage + globals.favicons.path + 'apple-touch-icon-60x60.png') 8 | link(rel='apple-touch-icon' sizes='72x72' href=globals.homepage + globals.favicons.path + 'apple-touch-icon-72x72.png') 9 | link(rel='apple-touch-icon' sizes='76x76' href=globals.homepage + globals.favicons.path + 'apple-touch-icon-76x76.png') 10 | link(rel='apple-touch-startup-image' media='(device-width: 320px) and (device-height: 480px) and (-webkit-device-pixel-ratio: 1)' href=globals.homepage + globals.favicons.path + 'apple-touch-startup-image-320x460.png') 11 | link(rel='apple-touch-startup-image' media='(device-width: 320px) and (device-height: 480px) and (-webkit-device-pixel-ratio: 2)' href=globals.homepage + globals.favicons.path + 'apple-touch-startup-image-640x920.png') 12 | link(rel='apple-touch-startup-image' media='(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2)' href=globals.homepage + globals.favicons.path + 'apple-touch-startup-image-640x1096.png') 13 | link(rel='apple-touch-startup-image' media='(device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2)' href=globals.homepage + globals.favicons.path + 'apple-touch-startup-image-750x1294.png') 14 | link(rel='apple-touch-startup-image' media='(device-width: 414px) and (device-height: 736px) and (orientation: landscape) and (-webkit-device-pixel-ratio: 3)' href=globals.homepage + globals.favicons.path + 'apple-touch-startup-image-1182x2208.png') 15 | link(rel='apple-touch-startup-image' media='(device-width: 414px) and (device-height: 736px) and (orientation: portrait) and (-webkit-device-pixel-ratio: 3)' href=globals.homepage + globals.favicons.path + 'apple-touch-startup-image-1242x2148.png') 16 | link(rel='apple-touch-startup-image' media='(device-width: 768px) and (device-height: 1024px) and (orientation: landscape) and (-webkit-device-pixel-ratio: 1)' href=globals.homepage + globals.favicons.path + 'apple-touch-startup-image-748x1024.png') 17 | link(rel='apple-touch-startup-image' media='(device-width: 768px) and (device-height: 1024px) and (orientation: landscape) and (-webkit-device-pixel-ratio: 2)' href=globals.homepage + globals.favicons.path + 'apple-touch-startup-image-1496x2048.png') 18 | link(rel='apple-touch-startup-image' media='(device-width: 768px) and (device-height: 1024px) and (orientation: portrait) and (-webkit-device-pixel-ratio: 1)' href=globals.homepage + globals.favicons.path + 'apple-touch-startup-image-768x1004.png') 19 | link(rel='apple-touch-startup-image' media='(device-width: 768px) and (device-height: 1024px) and (orientation: portrait) and (-webkit-device-pixel-ratio: 2)' href=globals.homepage + globals.favicons.path + 'apple-touch-startup-image-1536x2008.png') 20 | link(rel='icon' type='image/png' sizes='16x16' href=globals.homepage + globals.favicons.path + 'favicon-16x16.png') 21 | link(rel='icon' type='image/png' sizes='228x228' href=globals.homepage + globals.favicons.path + 'coast-228x228.png') 22 | link(rel='icon' type='image/png' sizes='32x32' href=globals.homepage + globals.favicons.path + 'favicon-32x32.png') 23 | link(rel='manifest' href=globals.homepage + globals.favicons.path + 'manifest.json') 24 | link(rel='shortcut icon' href=globals.homepage + globals.favicons.path + 'favicon.ico') 25 | link(rel='yandex-tableau-widget' href=globals.homepage + globals.favicons.path + 'yandex-browser-manifest.json') 26 | meta(name='apple-mobile-web-app-capable' content='yes') 27 | meta(name='apple-mobile-web-app-status-bar-style' content='black-translucent') 28 | meta(name='apple-mobile-web-app-title' content=globals.favicons.appName) 29 | meta(name='application-name' content=globals.favicons.appName) 30 | meta(name='mobile-web-app-capable' content='yes') 31 | meta(name='msapplication-TileColor' content=globals.favicons.background) 32 | meta(name='msapplication-TileImage' content=globals.homepage + globals.favicons.path + 'mstile-144x144.png') 33 | meta(name='msapplication-config' content=globals.homepage + globals.favicons.path + 'browserconfig.xml') 34 | meta(name='theme-color' content=globals.theme_color) 35 | -------------------------------------------------------------------------------- /source/layouts/_head.pug: -------------------------------------------------------------------------------- 1 | head 2 | meta(charset='utf-8') 3 | meta(http-equiv='content-language' content=globals.lang) 4 | meta(name='viewport' content='width=device-width, initial-scale=1, maximum-scale=5') 5 | meta(http-equiv='X-UA-Compatible' content='IE=edge') 6 | link(rel='author', type='text/plain', href=globals.homepage + '/humans.txt') 7 | 8 | title=globals.title 9 | 10 | include ./_metas.pug 11 | include ./_favicons.pug 12 | 13 | if globals.isProduction 14 | script(async src='https://www.googletagmanager.com/gtag/js?id=' + globals.ga) 15 | script. 16 | window.dataLayer = window.dataLayer || []; 17 | function gtag(){dataLayer.push(arguments);} 18 | gtag('js', new Date()); 19 | gtag('config', '#{globals.ga}'); 20 | -------------------------------------------------------------------------------- /source/layouts/_metas.pug: -------------------------------------------------------------------------------- 1 | meta(name='robots', content='index,follow') 2 | meta(http-equiv='cache-control', content='cache') 3 | meta(http-equiv='revisit-after', content='1 day') 4 | 5 | meta(name='application-name' content=globals.title) 6 | meta(property='og:title', content=globals.title) 7 | meta(name='twitter:title', content=globals.title) 8 | 9 | meta(name='description', content=globals.description) 10 | meta(property='og:description', content=globals.description) 11 | meta(itemprop='description', content=globals.description) 12 | meta(name='twitter:description', content=globals.description) 13 | 14 | - var image = globals.homepage + require('../images/share.jpg') 15 | 16 | meta(name='image' content=image) 17 | meta(itemprop='image' content=image) 18 | meta(property='og:image', content=image) 19 | meta(property='og:image:type', content='image/jpeg') 20 | meta(property='og:image:width', content='800') 21 | meta(property='og:image:height', content='600') 22 | meta(name='twitter:image:src', content=image) 23 | meta(name='twitter:card', content='summary_large_image') 24 | 25 | meta(name='mobile-web-app-capable' content='yes') 26 | meta(property='og:locale', content=globals.lang) 27 | meta(property='og:type', content='website') 28 | meta(property='og:url', content=globals.homepage) 29 | meta(property='og:site_name', content=globals.name) 30 | meta(itemprop='name', content=globals.name) 31 | meta(name='twitter:site', content='@' + globals.author.twitter) 32 | meta(name='twitter:creator', content='@' + globals.author.twitter) 33 | //- meta(property='fb:admins', content='Facebook numeric ID') 34 | -------------------------------------------------------------------------------- /source/layouts/_scripts.pug: -------------------------------------------------------------------------------- 1 | block scripts 2 | script. 3 | // Block scripts 4 | 5 | if globals.isProduction 6 | script(type='text/javascript' src='//s7.addthis.com/js/300/addthis_widget.js#pubid=ra-5c1eaed71a17af3a') 7 | -------------------------------------------------------------------------------- /source/layouts/default.pug: -------------------------------------------------------------------------------- 1 | doctype html 2 | html(lang=globals.lang) 3 | include ./_head.pug 4 | body.layout-blank 5 | block content 6 | include ./_scripts.pug 7 | -------------------------------------------------------------------------------- /source/static/_redirects: -------------------------------------------------------------------------------- 1 | # Redirect default Netlify subdomain to primary domain 2 | http://starter-kit.netlify.com/* http://starter-kit.nandomoreira.dev/:splat 301! 3 | https://starter-kit.netlify.com/* https://starter-kit.nandomoreira.dev/:splat 301! 4 | -------------------------------------------------------------------------------- /source/static/humans.txt: -------------------------------------------------------------------------------- 1 | /* TEAM */ 2 | Web developer: Fernando Moreira 3 | Site: https://nandomoreira.dev 4 | Email: nandomoreira.me [at] gmail.com 5 | Twitter: @oseunando 6 | From: Curitiba, Paraná, Brazil 7 | 8 | /* SITE */ 9 | Language: English 10 | Doctype: HTML5 11 | IDE: Visual Studio Code 12 | Tech stack: Javascript, Webpack, Babel, HTML5, CSS3, SASS 13 | -------------------------------------------------------------------------------- /source/static/robots.txt: -------------------------------------------------------------------------------- 1 | # Allow crawling of all content 2 | User-agent: * 3 | Disallow: -------------------------------------------------------------------------------- /source/styles/_base.scss: -------------------------------------------------------------------------------- 1 | // Blocks 2 | html, 3 | body, 4 | p, 5 | ol, 6 | ul, 7 | li, 8 | dl, 9 | dt, 10 | dd, 11 | blockquote, 12 | figure, 13 | fieldset, 14 | legend, 15 | textarea, 16 | pre, 17 | iframe, 18 | hr, 19 | h1, 20 | h2, 21 | h3, 22 | h4, 23 | h5, 24 | h6 { 25 | margin: 0; 26 | padding: 0; 27 | } 28 | 29 | // List 30 | ul { 31 | list-style: none; 32 | } 33 | 34 | // Form 35 | button, 36 | input, 37 | select, 38 | textarea { 39 | margin: 0; 40 | } 41 | 42 | // Box sizing 43 | html { 44 | box-sizing: border-box; 45 | font-family: sans-serif; 46 | font-size: $fontSizeBase; 47 | /* stylelint-disable */ 48 | -webkit-text-size-adjust: 100%; 49 | -ms-text-size-adjust: 100%; 50 | /* stylelint-enable */ 51 | } 52 | 53 | *, 54 | *::before, 55 | *::after { 56 | box-sizing: inherit; 57 | } 58 | 59 | body { 60 | background-color: $backgroundColor; 61 | color: $textColor; 62 | font-family: $fontFamilyBase; 63 | font-size: 1rem /* 16/16 */; 64 | font-weight: $fontWeightBase; 65 | letter-spacing: -0.05px; 66 | line-height: $lineHeightBase; 67 | } 68 | 69 | // Headings 70 | h1, 71 | h2, 72 | h3, 73 | h4, 74 | h5, 75 | h6 { 76 | font-family: $fontFamilyHeading; 77 | font-size: 100%; 78 | font-weight: 800; 79 | margin: 0 0 1.875rem /* 30/16 */; 80 | } 81 | 82 | a { 83 | color: $linkColor; 84 | text-decoration: none; 85 | 86 | &:hover { 87 | color: $linkColorHover; 88 | text-decoration: underline; 89 | } 90 | } 91 | 92 | // Media 93 | img, 94 | embed, 95 | iframe, 96 | object, 97 | audio, 98 | video { 99 | height: auto; 100 | max-width: 100%; 101 | } 102 | 103 | // Iframe 104 | iframe { 105 | border: 0; 106 | } 107 | 108 | // Table 109 | table { 110 | border-collapse: collapse; 111 | border-spacing: 0; 112 | } 113 | 114 | td, 115 | th { 116 | padding: 0; 117 | text-align: left; 118 | } 119 | 120 | code, 121 | pre { 122 | font-family: $fontFamilyMonospace; 123 | font-size: 0.875rem /* 14/16 */; 124 | } 125 | 126 | pre { 127 | white-space: pre; 128 | white-space: pre-wrap; 129 | word-wrap: break-word; 130 | } 131 | 132 | small { 133 | font-size: 80%; 134 | } 135 | 136 | button, 137 | input, 138 | select, 139 | textarea { 140 | font-family: inherit; 141 | font-size: 100%; 142 | margin: 0; 143 | } 144 | 145 | textarea { 146 | vertical-align: top; 147 | } 148 | 149 | table { 150 | border-collapse: collapse; 151 | border-spacing: 0; 152 | } 153 | 154 | hr { 155 | border: 0; 156 | border-bottom: $borderBase; 157 | margin: 1.875rem /* 30/16 */ 0; 158 | } 159 | -------------------------------------------------------------------------------- /source/styles/_mixins.scss: -------------------------------------------------------------------------------- 1 | /* 2 | Usage 3 | 4 | .container { 5 | width: 1200px; 6 | 7 | @include media(min-width 480px) { 8 | font-size: 1.2rem; 9 | } 10 | 11 | @include media(max-width 1200px) { 12 | width: 700px; 13 | } 14 | } 15 | */ 16 | 17 | $default-feature: max-width; 18 | 19 | @mixin media($query: $feature $value) { 20 | @if length($query)==1 { 21 | @media screen and ($default-feature: nth($query, 1)) { 22 | @content; 23 | } 24 | } 25 | 26 | @else { 27 | $loop-to: length($query); 28 | $media-query: 'screen and '; 29 | 30 | @if length($query) % 2 !=0 { 31 | $loop-to: $loop-to - 1; 32 | } 33 | 34 | $i: 1; 35 | 36 | @while $i <=$loop-to { 37 | $media-query: $media-query + '('+ nth($query, $i) + ': '+ nth($query, $i + 1) + ') '; 38 | 39 | @if ($i + 1) !=$loop-to { 40 | $media-query: $media-query + 'and '; 41 | } 42 | 43 | $i: $i+2; 44 | } 45 | 46 | @media #{$media-query} { 47 | @content; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /source/styles/_vars.scss: -------------------------------------------------------------------------------- 1 | // Color palette 2 | $blackColor: #000; 3 | $whiteColor: #fff; 4 | $greyColor: #5b5b5b; 5 | $silverColor: #d8d8d8; 6 | $primaryColor: #0b7ff5; 7 | // $textColor: lighten($blackColor, 15%); 8 | $textColor: $whiteColor; 9 | // $linkColor: $primaryColor; 10 | $linkColor: $whiteColor; 11 | $linkColorHover: lighten($linkColor, 10%); 12 | // $backgroundColor: darken($whiteColor, 2%); 13 | $backgroundColor: $primaryColor; 14 | $borderColor: rgba($blackColor, .1); 15 | 16 | $fontFamilyBase: 'Open Sans', -apple-system, system-ui, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; 17 | $fontFamilyHeading: 'Poppins', $fontFamilyBase; 18 | $fontFamilySerif: 'Spectral', 'Georgia', 'Times New Roman', 'Times', serif; 19 | $fontFamilyMonospace: SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace; 20 | 21 | $fontSizeBase: 16px; 22 | $lineHeightBase: 1.6; 23 | $fontWeightBase: 500; 24 | $letterSpacingBase: -0.05px; 25 | 26 | // Borders 27 | $borderBase: .0625rem /* 1/16 */ solid $borderColor; 28 | $borderRadiusBase: .25rem; /* 4/16 */ 29 | $borderRadiusSmall: .125rem; /* 2/16 */ 30 | $borderRadiusLarge: .375rem; /* 6/16 */ 31 | 32 | $breakpoint-sm: 576px; 33 | $breakpoint-md: 768px; 34 | $breakpoint-lg: 992px; 35 | $breakpoint-xl: 1200px; 36 | -------------------------------------------------------------------------------- /source/styles/main.scss: -------------------------------------------------------------------------------- 1 | @import 'vars'; 2 | @import 'base'; 3 | -------------------------------------------------------------------------------- /tasks/build.js: -------------------------------------------------------------------------------- 1 | import webpack from 'webpack' 2 | import { series } from 'gulp' 3 | import { webpackConfig } from './config' 4 | import { favicons } from './favicons' 5 | import { copyFiles } from './static' 6 | 7 | const _webpack = () => 8 | new Promise(resolve => webpack(webpackConfig, (err, stats) => { 9 | if (err) console.log('Webpack', err) 10 | console.log(stats.toString({ /* stats options */ })) 11 | resolve() 12 | })) 13 | 14 | const _task = series(_webpack, favicons, copyFiles) 15 | _task.description = '{{ build all scripts }}' 16 | 17 | export const build = _task 18 | -------------------------------------------------------------------------------- /tasks/config/base.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config() 2 | 3 | export const { 4 | NODE_ENV, 5 | DOTENV_CONFIG_EXAMPLE 6 | } = process.env 7 | 8 | const config = require('../../site-config.json') 9 | export const pkg = require('../../package.json') 10 | 11 | export const env = NODE_ENV || 'development' 12 | export const isProduction = env === 'production' 13 | 14 | export const homepage = isProduction ? pkg.homepage : 'http://localhost:3000' 15 | export const ga = isProduction ? config.ga : 'UA-000000000-1' 16 | 17 | delete pkg.main 18 | delete pkg.engines 19 | delete pkg.scripts 20 | delete pkg.dependencies 21 | delete pkg.devDependencies 22 | 23 | export const siteConfig = { 24 | ...pkg, 25 | ...{ env, isProduction, homepage }, 26 | ...config, 27 | ...{ ga } 28 | } 29 | -------------------------------------------------------------------------------- /tasks/config/index.js: -------------------------------------------------------------------------------- 1 | export * from './base' 2 | export * from './paths' 3 | export * from './plugins' 4 | export * from './webpack' 5 | -------------------------------------------------------------------------------- /tasks/config/paths.js: -------------------------------------------------------------------------------- 1 | import { resolve, join } from 'path' 2 | 3 | const _rootPath = resolve(__dirname, '..', '..') 4 | const _srcPath = join(_rootPath, 'source') 5 | const _distPath = join(_rootPath, 'dist') 6 | 7 | export const paths = { 8 | root: _rootPath, 9 | modules: join(_rootPath, 'node_modules'), 10 | src: _srcPath, 11 | dist: _distPath, 12 | static: join(_srcPath, 'static'), 13 | components: join(_srcPath, 'components'), 14 | pages: join(_srcPath, 'pages'), 15 | styles: join(_srcPath, 'scss'), 16 | scripts: join(_srcPath, 'scripts') 17 | } 18 | -------------------------------------------------------------------------------- /tasks/config/plugins.js: -------------------------------------------------------------------------------- 1 | import { isProduction, siteConfig } from './base' 2 | import { paths } from './paths' 3 | 4 | const plugins = {} 5 | 6 | plugins.size = require('gulp-size') 7 | plugins.favicons = require('favicons').stream 8 | plugins.browserSync = require('browser-sync').create() 9 | 10 | export const $ = plugins 11 | 12 | export const sassConfig = { 13 | sourceMap: !isProduction, 14 | includePaths: [ 15 | paths.modules, 16 | paths.styles, 17 | paths.components 18 | ] 19 | } 20 | 21 | export const faviconsConfig = { 22 | appName: siteConfig.name, 23 | appDescription: siteConfig.description, 24 | developerName: siteConfig.author.name, 25 | developerURL: siteConfig.author.site, 26 | background: '#fff', 27 | path: '/favicons/', 28 | url: `${siteConfig.homepage}/`, 29 | display: 'standalone', 30 | orientation: 'portrait', 31 | start_url: '/?homescreen=1', 32 | version: 1.0, 33 | logging: false, 34 | html: 'favicons.html', 35 | lang: siteConfig.lang, 36 | pipeHTML: true, 37 | replace: true 38 | } 39 | 40 | export const serviceWorker = { 41 | safeToUseOptionalCaches: true, 42 | caches: { 43 | main: ['index.html'], 44 | additional: ['*.js'] 45 | }, 46 | navigateFallbackURL: '/', 47 | autoUpdate: true, 48 | responseStrategy: 'cache-first', 49 | ServiceWorker: { 50 | events: true 51 | }, 52 | AppCache: { 53 | events: true 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /tasks/config/webpack.js: -------------------------------------------------------------------------------- 1 | import webpack from 'webpack' 2 | import MiniCssExtractPlugin from 'mini-css-extract-plugin' 3 | import HtmlWebpackPlugin from 'html-webpack-plugin' 4 | import { CleanWebpackPlugin } from 'clean-webpack-plugin' 5 | import OfflinePlugin from 'offline-plugin' 6 | 7 | import { join, resolve } from 'path' 8 | import { paths } from './paths' 9 | import { 10 | env, 11 | pkg, 12 | isProduction, 13 | siteConfig 14 | } from './base' 15 | import { 16 | serviceWorker, 17 | sassConfig, 18 | faviconsConfig 19 | } from './plugins' 20 | 21 | const outputFile = '[name].bundle.js' 22 | const plugins = [] 23 | 24 | plugins.push(new webpack.DefinePlugin({ 25 | VERSION: JSON.stringify(pkg.version) 26 | })) 27 | 28 | plugins.push(new webpack.BannerPlugin({ 29 | banner: `${pkg.name} - ${pkg.description} 30 | @link ${pkg.homepage} 31 | @version ${pkg.version} 32 | @license ${pkg.license} 33 | @author ${pkg.author.name} <${pkg.author.email}> | ${pkg.author.site}` 34 | })) 35 | 36 | plugins.push(new CleanWebpackPlugin()) 37 | 38 | plugins.push(new HtmlWebpackPlugin({ 39 | template: resolve(paths.src, 'index.pug'), 40 | hash: true, 41 | cache: true, 42 | templateParameters: { 43 | globals: { ...siteConfig, ...{ favicons: faviconsConfig } } 44 | } 45 | })) 46 | 47 | plugins.push(new MiniCssExtractPlugin({ 48 | filename: 'styles/style.[contenthash].css' 49 | })) 50 | 51 | plugins.push(new OfflinePlugin(serviceWorker)) 52 | 53 | export const webpackConfig = { 54 | mode: env, 55 | devtool: isProduction ? 'source-map' : '', 56 | entry: join(paths.src, 'index.js'), 57 | output: { 58 | publicPath: '/', 59 | path: paths.dist, 60 | filename: outputFile 61 | }, 62 | context: paths.dist, 63 | module: { 64 | rules: [{ 65 | test: /\.pug/, 66 | loader: 'pug-loader', 67 | query: { 68 | pretty: !isProduction 69 | } 70 | }, { 71 | test: /\.scss/, 72 | use: [ 73 | 'style-loader', 74 | MiniCssExtractPlugin.loader, 75 | { 76 | loader: 'css-loader', 77 | options: { 78 | importLoaders: 1 79 | } 80 | }, 81 | 'postcss-loader', 82 | { 83 | loader: 'sass-loader', 84 | options: sassConfig 85 | } 86 | ] 87 | }, { 88 | test: /\.jpe?g$|\.gif$|\.png$|\.svg$/, 89 | use: { 90 | loader: 'file-loader', 91 | options: { 92 | outputPath: 'images', 93 | name: '[name]-[hash].[ext]' 94 | } 95 | } 96 | }, { 97 | test: /\.m?js$/, 98 | exclude: /(node_modules|bower_components)/, 99 | use: { 100 | loader: 'babel-loader', 101 | options: { 102 | presets: ['@babel/preset-env'], 103 | plugins: ['@babel/plugin-proposal-object-rest-spread'] 104 | } 105 | } 106 | }] 107 | }, 108 | resolve: { 109 | extensions: ['.js'], 110 | modules: [ 111 | paths.modules, 112 | paths.scripts 113 | ] 114 | }, 115 | plugins 116 | } 117 | -------------------------------------------------------------------------------- /tasks/favicons.js: -------------------------------------------------------------------------------- 1 | import { src, dest, parallel } from 'gulp' 2 | import { paths, $, faviconsConfig } from './config' 3 | 4 | const _favicons = () => 5 | src([`${paths.src}/images/icon.png`]) 6 | .pipe($.favicons(faviconsConfig)) 7 | .pipe(dest(`${paths.dist}${faviconsConfig.path}`)) 8 | 9 | const _task = parallel(_favicons) 10 | _task.description = '{{ generate favicons }}' 11 | 12 | export const favicons = _task 13 | -------------------------------------------------------------------------------- /tasks/index.js: -------------------------------------------------------------------------------- 1 | import { server } from './watch' 2 | 3 | export * from './static' 4 | export * from './favicons' 5 | export * from './build' 6 | export * from './watch' 7 | 8 | export default server 9 | -------------------------------------------------------------------------------- /tasks/static.js: -------------------------------------------------------------------------------- 1 | import { src, dest, parallel } from 'gulp' 2 | import { paths, $ } from './config' 3 | 4 | const _static = () => 5 | src([`${paths.static}/*`]) 6 | .pipe($.size()) 7 | .pipe(dest(paths.dist)) 8 | 9 | const _images = () => 10 | src([`${paths.src}/images/*.{png,jpg,jpeg,gif}`]) 11 | .pipe($.size()) 12 | .pipe(dest(`${paths.dist}/images`)) 13 | 14 | const _task = parallel(_static, _images) 15 | _task.description = '{{ Copy static files and images }}' 16 | 17 | export const copyFiles = _task 18 | -------------------------------------------------------------------------------- /tasks/watch.js: -------------------------------------------------------------------------------- 1 | import webpack from 'webpack' 2 | import webpackDevMiddleware from 'webpack-dev-middleware' 3 | import webpackHotMiddleware from 'webpack-hot-middleware' 4 | import gulp from 'gulp' 5 | import { paths, $, webpackConfig } from './config' 6 | import { build } from './build' 7 | 8 | const bundler = webpack(webpackConfig) 9 | 10 | const _watchScripts = () => 11 | gulp.watch(`${paths.src}/**/*.js`, build) 12 | 13 | const _bSync = () => { 14 | $.browserSync.init({ 15 | server: { 16 | baseDir: paths.dist 17 | }, 18 | middleware: [ 19 | webpackDevMiddleware(bundler, { /* options */ }), 20 | webpackHotMiddleware(bundler) 21 | ] 22 | }) 23 | 24 | _watchScripts() 25 | gulp.watch(`${paths.dist}/**/*.{html,css,js}`, $.browserSync.reload()) 26 | } 27 | 28 | const _build = gulp.series(build) 29 | const _watch = gulp.series(_watchScripts) 30 | const _serve = gulp.series(_build, _bSync) 31 | 32 | _watch.description = '{{ watch for changes to all source }}' 33 | _serve.description = '{{ serve compiled source on local server at port 3000 }}' 34 | 35 | export const watch = _watch 36 | export const server = _serve 37 | --------------------------------------------------------------------------------