├── .babelrc ├── .browserslistrc ├── .eslintrc ├── .gitignore ├── .stylelintrc ├── README.md ├── gulpfile.babel.js ├── config.js ├── index.js ├── tasks │ ├── assets.js │ ├── build.js │ ├── clean.js │ ├── copy.js │ ├── deploy.js │ ├── dev.js │ ├── scripts.js │ ├── server.js │ ├── styles.js │ ├── templates.js │ └── watch.js └── util │ ├── env.js │ └── errorHandler.js ├── package-lock.json ├── package.json ├── src ├── assets │ ├── fonts │ │ └── .gitkeep │ └── img │ │ └── .gitkeep ├── robots.txt ├── scripts │ ├── app.js │ ├── components │ │ └── navbar.js │ └── utils │ │ ├── closest.polyfill.js │ │ └── matches.polyfill.js ├── styles │ ├── 1-settings │ │ ├── _breakpoints.scss │ │ ├── _colors.scss │ │ ├── _global.scss │ │ ├── _spacing.scss │ │ ├── _typography.scss │ │ └── _utilities.scss │ ├── 2-tools │ │ ├── _breakpoints.scss │ │ ├── _generate-utility.scss │ │ ├── _make-responsive.scss │ │ └── _ratio.scss │ ├── 3-generic │ │ ├── _font-face.scss │ │ ├── _print.scss │ │ └── _sanitize.scss │ ├── 4-elements │ │ ├── _blockquote.scss │ │ ├── _document.scss │ │ ├── _headings.scss │ │ ├── _links.scss │ │ ├── _lists.scss │ │ ├── _media.scss │ │ ├── _paragraphs.scss │ │ └── _tables.scss │ ├── 5-objects │ │ └── _container..scss │ ├── 6-components │ │ └── _buttons.scss │ ├── 7-modules │ │ └── _navbar.scss │ ├── 8-utilities │ │ ├── _ratio.scss │ │ └── _utilities.scss │ ├── _shame.scss │ └── main.scss └── templates │ ├── components │ ├── footer.twig │ └── navbar.twig │ ├── layouts │ └── default.twig │ └── pages │ ├── 404.twig │ ├── index.twig │ ├── preview.twig │ └── starter.twig ├── webpack.config.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "targets": { "node": "current" } 7 | } 8 | ] 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /.browserslistrc: -------------------------------------------------------------------------------- 1 | # Browsers that we support 2 | # https://github.com/browserslist/browserslist#best-practices 3 | defaults 4 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["eslint:recommended"], 3 | "parserOptions": { 4 | "ecmaVersion": 6, 5 | #"ecmaVersion": 2018, 6 | "sourceType": "module" 7 | }, 8 | "env": { 9 | "browser": true, 10 | "node": true 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Dependency directories 2 | node_modules 3 | bower_components 4 | dist 5 | 6 | # Optional npm cache directory 7 | .npm 8 | 9 | # SASS Cache 10 | .sass-cache 11 | .sass-cache/* 12 | 13 | # Logs 14 | logs 15 | *.log 16 | npm-debug.log* 17 | 18 | # OSX 19 | *.DS_Store 20 | .AppleDouble 21 | .LSOverride 22 | 23 | # Windows 24 | Thumbs.db 25 | ehthumbs.db 26 | 27 | # Misc 28 | .publish 29 | -------------------------------------------------------------------------------- /.stylelintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "stylelint-config-standard", 4 | "stylelint-config-recommended-scss" 5 | ], 6 | "plugins": [ 7 | "stylelint-order" 8 | ], 9 | "rules": { 10 | "at-rule-empty-line-before": null, 11 | "at-rule-name-space-after": "always", 12 | "at-rule-no-unknown": null, 13 | "block-closing-brace-empty-line-before": null, 14 | "block-closing-brace-newline-after": null, 15 | "block-no-empty": null, 16 | "block-opening-brace-space-before": null, 17 | "declaration-empty-line-before": null, 18 | "max-empty-lines": 2, 19 | "number-leading-zero": null, 20 | "no-descending-specificity": null, 21 | "rule-empty-line-before": null, 22 | "selector-list-comma-newline-after": "always", 23 | "selector-pseudo-element-colon-notation": null, 24 | "font-family-no-duplicate-names": null, 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # I use the following boilerplate these days which is strictly based on TailwindCSS https://github.com/tomaszbujnowicz/laravel-mix-tailwindcss-purgecss 2 | 3 | # Hybrid Utility ITCSS - Front-end Boilerplate 4 | 5 | **🚀 ITCSS Architecture + CSS Utilities + Gulp 4 + Webpack 4 + Babel + Live Reload + Twig.js** 6 | 7 | These tools make it a solid front-end boilerplate to get a new project off the ground. 8 | Based on best pieces from Bootstrap, Tailwind CSS and years of experience. 9 | 10 | ## :gift: Features 11 | | Features | Description | 12 | | :------------- | :------------- | 13 | | Task Runner | [Gulp](http://gulpjs.com/) 14 | | CSS | [SASS](http://sass-lang.com/), [ITCSS](https://developer.helpscout.com/seed/glossary/itcss/), [CSS Guidelines](https://cssguidelin.es/) 15 | | CSS Tools | [Autoprefixer](https://github.com/postcss/autoprefixer), [Source Maps](https://www.npmjs.com/package/gulp-sourcemaps), [Stylelint](https://stylelint.io/) 16 | | JS | [Webpack](https://webpack.js.org/), [Babel](http://babeljs.io/), [ESLint](http://eslint.org/) 17 | | Live Reload | [BrowserSync](http://www.browsersync.io/) 18 | | HTML Templates | [Twig.js](https://github.com/twigjs/twig.js) 19 | | Deployment | [GitHub Pages](https://www.npmjs.com/package/gulp-gh-pages) 20 | 21 | ## Usage 22 | 23 | ### Requirements 24 | Make sure all dependencies have been installed before moving on: 25 | 26 | * [yarn](https://yarnpkg.com/lang/en/) or [npm](https://www.npmjs.com/get-npm) 27 | * [Node.js](https://nodejs.org/en/download/) >= 8.16.0 28 | * [Gulp](http://gulpjs.com/) 29 | 30 | ### Quick start: Installation 31 | Clone this repository and run 32 | - `yarn` or `npm install` to install dependencies 33 | 34 | ### Tasks 35 | | Task Name | Description | Environment | 36 | | :------------- | :------------- | :------------- | 37 | | `yarn start` or `npm run start` | Generate a development environment, start the server and watch for changes | Development 38 | | `yarn watch` or `npm run watch` | Start the server and watch for changes | Development 39 | | `yarn build` or `npm run build` | Compile production code | Production 40 | | `yarn deploy` or `npm run deploy` | Compile production code and deploy to GitHub Pages | Production 41 | 42 | ## Structure 43 | 44 | ``` 45 | |--dist/ # → Static version of the website ready to upload (never edit) 46 | | 47 | |--gulpfile.babel.js/ # → Gulpfile config and tasks 48 | |--node_modules/ # → Node.js packages (never edit) 49 | | 50 | |--src/ # → Source files 51 | | |--assets/ # → Assets 52 | | | |--fonts/ # → Assets: Fonts 53 | | | |--img/ # → Assets: Images 54 | | 55 | | |--scripts/ # → JS 56 | | | |--components/ # → Components 57 | | | |--utils/ # → Utils 58 | | | |--app.js # → Main file 59 | | 60 | | |--styles/ # → Styles: ITCSS Architecture + CSS Utilities 61 | | | |--1-settings/ # → Settings 62 | | | |--2-tools/ # → Tools 63 | | | |--3-generic/ # → Generic 64 | | | |--4-elements/ # → Elements 65 | | | |--5-objects/ # → Objects 66 | | | |--6-components/ # → Components 67 | | | |--7-modules/ # → Modules 68 | | | |--8-utilities/ # → Utilities 69 | | | |--main.scss # → Main file 70 | | 71 | | |--templates/ # → Templates (Twig.js) 72 | | | |--layouts/ # → Layouts 73 | | | |--components/ # → Components 74 | | | |--pages/ # → Pages 75 | | 76 | |--.babelrc # → Babel presets 77 | |--.browserslistrc # → Browserslist config, browsers that we support 78 | |--.eslintrc # → ESLint config 79 | |--.gitignore # → Gitignore 80 | |--.stylelintrc # → Stylelint config 81 | |--package-lock.json # → NPM lock file (never edit) 82 | |--package.json # → Node.js dependencies and scripts 83 | |--webpack.config.js # → Webpack config 84 | |--yarn.lock # → Yarn lock file (never edit) 85 | ``` 86 | 87 | ## Copyright and license 88 | 89 | Copyright 2019 Tomasz Bujnowicz under the [MIT license](http://opensource.org/licenses/MIT). 90 | -------------------------------------------------------------------------------- /gulpfile.babel.js/config.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @title Config 3 | */ 4 | 5 | // Paths 6 | export const paths = { 7 | src: './src', 8 | dest: './dist', 9 | deploy: './dist/**/*', 10 | styles: { 11 | src: 'src/styles/main.scss', 12 | watch: 'src/styles/**/*.scss', 13 | modules: 'src/modules/**/*.scss', 14 | dest: 'dist/css', 15 | lint: 'src/styles/**/*.s+(a|c)ss' 16 | }, 17 | scripts: { 18 | src: './src/scripts/app.js', 19 | watch: 'src/scripts/**/*.js', 20 | modules: 'src/modules/**/*.js', 21 | dest: 'dist/js', 22 | }, 23 | templates: { 24 | src: 'src/templates/pages/*.{twig,html}', 25 | watch: 'src/templates/**/*.{twig,html}', 26 | modules: 'src/modules/**/*.{twig,html}', 27 | dest: 'dist/' 28 | }, 29 | assets: { 30 | src: 'src/assets/**/*', 31 | dest: 'dist/assets' 32 | }, 33 | copy: { 34 | src: 'src/robots.txt', 35 | dest: 'dist/' 36 | } 37 | }; 38 | -------------------------------------------------------------------------------- /gulpfile.babel.js/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @title gulpfile.babel.js 3 | * @description A directory file loader to include all the gulp tasks 4 | */ 5 | 6 | // Tasks 7 | import { build } from './tasks/build'; 8 | import { deploy } from './tasks/deploy'; 9 | import { watch } from './tasks/watch'; 10 | import { dev } from './tasks/dev'; 11 | 12 | exports.build = build; 13 | exports.deploy = deploy; 14 | exports.watch = watch; 15 | exports.default = dev; 16 | -------------------------------------------------------------------------------- /gulpfile.babel.js/tasks/assets.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @title Assets 3 | * @description A task to copy assets. 4 | */ 5 | 6 | // Dependencies 7 | import { src, dest } from 'gulp'; 8 | import babel from 'gulp-babel'; 9 | import plumber from 'gulp-plumber'; 10 | import changed from "gulp-changed"; 11 | import errorHandler from '../util/errorHandler.js'; 12 | 13 | // Config 14 | import { paths } from "../config"; 15 | 16 | // Task 17 | export function assets() { 18 | return src(paths.assets.src) 19 | .pipe(plumber({errorHandler})) 20 | .pipe(changed(paths.assets.dest)) 21 | .pipe(dest(paths.assets.dest)); 22 | } 23 | -------------------------------------------------------------------------------- /gulpfile.babel.js/tasks/build.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @title Build 3 | * @description A task to compile production code. 4 | */ 5 | 6 | // Dependencies 7 | import { series, parallel } from 'gulp'; 8 | 9 | // Tasks 10 | import { clean } from './clean'; 11 | import { styles } from './styles'; 12 | import { scripts } from './scripts'; 13 | import { templates } from './templates'; 14 | import { assets } from './assets'; 15 | import { copy } from './copy'; 16 | 17 | // Config 18 | import { paths } from "../config"; 19 | 20 | export const build = series( 21 | clean, 22 | parallel(styles, scripts, templates, assets, copy) 23 | ); 24 | -------------------------------------------------------------------------------- /gulpfile.babel.js/tasks/clean.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @title Clean 3 | * @description A task to delete the output directory. 4 | */ 5 | 6 | // Dependencies 7 | import del from 'del'; 8 | 9 | // Config 10 | import { paths } from "../config"; 11 | 12 | // Task 13 | export function clean() { 14 | return del([ paths.dest ]); 15 | } 16 | -------------------------------------------------------------------------------- /gulpfile.babel.js/tasks/copy.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @title Copy 3 | * @description A task to copy font files to the output directory. 4 | */ 5 | 6 | // Dependencies 7 | import { src, dest } from 'gulp'; 8 | import changed from "gulp-changed"; 9 | 10 | // Config 11 | import { paths } from "../config"; 12 | 13 | // Task 14 | export function copy() { 15 | return src(paths.copy.src) 16 | .pipe(changed(paths.copy.dest)) 17 | .pipe(dest(paths.copy.dest)) 18 | } 19 | -------------------------------------------------------------------------------- /gulpfile.babel.js/tasks/deploy.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @title Deploy 3 | * @description Publish contents to Github pages. 4 | */ 5 | 6 | // Dependencies 7 | import { src } from 'gulp'; 8 | import ghPages from 'gulp-gh-pages'; 9 | 10 | // Config 11 | import { paths } from "../config"; 12 | 13 | // Task 14 | export function deploy() { 15 | return src(paths.deploy) 16 | .pipe(ghPages()) 17 | } 18 | -------------------------------------------------------------------------------- /gulpfile.babel.js/tasks/dev.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @title Dev 3 | * @description A task to generate a development environment, 4 | * start the server and watch for changes. 5 | */ 6 | 7 | // Dependencies 8 | import { series } from 'gulp'; 9 | 10 | // Tasks 11 | import { build } from './build'; 12 | import { watch } from './watch'; 13 | 14 | export const dev = series( 15 | build, 16 | watch 17 | ); 18 | -------------------------------------------------------------------------------- /gulpfile.babel.js/tasks/scripts.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @title Scripts 3 | * @description A task to concatenate and compress js files via webpack. 4 | */ 5 | 6 | // Dependencies 7 | import { src, dest, series } from 'gulp'; 8 | import gulpif from 'gulp-if'; 9 | import babel from 'gulp-babel'; 10 | import webpack from 'webpack'; 11 | import gulpWebpack from 'webpack-stream'; 12 | import gulpEslint from 'gulp-eslint'; 13 | import plumber from 'gulp-plumber'; 14 | import errorHandler from '../util/errorHandler.js'; 15 | import { isProd } from "../util/env.js" 16 | 17 | // Config 18 | import { paths } from "../config"; 19 | 20 | // Task 21 | export function esTranspile() { 22 | return src(paths.scripts.src) 23 | .pipe(plumber({errorHandler})) 24 | .pipe(gulpWebpack(require('../../webpack.config.js'), webpack)) 25 | .pipe(dest(paths.scripts.dest)) 26 | } 27 | 28 | export function esLint() { 29 | return src(paths.scripts.src) 30 | .pipe(gulpEslint()) 31 | .pipe(gulpEslint.format()) 32 | .pipe(gulpif(isProd, gulpEslint.failAfterError())) 33 | } 34 | 35 | export const scripts = series(esLint, esTranspile); 36 | -------------------------------------------------------------------------------- /gulpfile.babel.js/tasks/server.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @title Server 3 | * @description A task to initialise a local server. 4 | */ 5 | 6 | // Dependencies 7 | import browserSync from 'browser-sync'; 8 | 9 | // Config 10 | import { paths } from "../config"; 11 | 12 | // Task 13 | // const server = browserSync.create(); 14 | 15 | export function serve(cb) { 16 | browserSync.init({ 17 | server: { 18 | baseDir: [ paths.dest ] 19 | }, 20 | notify: false 21 | }); 22 | cb(); 23 | } 24 | 25 | export function reload(cb) { 26 | browserSync.reload(); 27 | cb(); 28 | } 29 | -------------------------------------------------------------------------------- /gulpfile.babel.js/tasks/styles.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @title Styles 3 | * @description A task to compile Sass to CSS. 4 | */ 5 | 6 | // Dependencies 7 | import { src, dest, series } from 'gulp'; 8 | import gulpif from 'gulp-if'; 9 | import plumber from 'gulp-plumber'; 10 | import sass from 'gulp-sass'; 11 | import sassGlob from 'gulp-sass-glob'; 12 | import sourcemaps from 'gulp-sourcemaps'; 13 | import postcss from 'gulp-postcss'; 14 | import autoprefixer from 'autoprefixer'; 15 | import gulpStylelint from 'gulp-stylelint'; 16 | import errorHandler from '../util/errorHandler.js'; 17 | import { isProd } from '../util/env.js'; 18 | 19 | import { reload } from '../tasks/server'; 20 | import browserSync from 'browser-sync' 21 | 22 | // Config 23 | import { paths } from "../config"; 24 | 25 | export function scss() { 26 | return src(paths.styles.src) 27 | .pipe(plumber({errorHandler})) 28 | .pipe(gulpif(isProd, sourcemaps.init() )) 29 | .pipe(sassGlob()) 30 | .pipe(sass({ 31 | includePaths: ['node_modules'], 32 | outputStyle: 'compressed' 33 | })) 34 | .pipe(postcss([ autoprefixer() ])) 35 | .pipe(gulpif(isProd, sourcemaps.write('.') )) 36 | .pipe(dest(paths.styles.dest)) 37 | .pipe(browserSync.stream()) 38 | } 39 | 40 | export function stylelint() { 41 | return src(paths.styles.watch) 42 | .pipe(gulpStylelint({ 43 | failAfterError: isProd, 44 | reporters: [{ formatter: 'string', console: true }], 45 | syntax: 'scss' 46 | })); 47 | } 48 | 49 | export const styles = series(stylelint, scss); 50 | -------------------------------------------------------------------------------- /gulpfile.babel.js/tasks/templates.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @title Templates 3 | * @description A task to compile templates via Twig.js 4 | */ 5 | 6 | // Dependencies 7 | import { src, dest } from 'gulp'; 8 | import plumber from 'gulp-plumber'; 9 | import twig from 'gulp-twig'; 10 | import errorHandler from '../util/errorHandler.js'; 11 | import beautify from 'gulp-jsbeautifier'; 12 | 13 | // Config 14 | import { paths } from "../config"; 15 | 16 | // Task 17 | export function templates() { 18 | return src(paths.templates.src) 19 | .pipe(plumber({errorHandler})) 20 | .pipe(twig()) 21 | .pipe(beautify({ indent_size: 2 })) 22 | .pipe(dest(paths.templates.dest)) 23 | }; 24 | -------------------------------------------------------------------------------- /gulpfile.babel.js/tasks/watch.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @title Watch 3 | * @description A task to start the server and watch for changes. 4 | */ 5 | 6 | // Dependencies 7 | import gulp from 'gulp'; 8 | import { series } from 'gulp'; 9 | 10 | // Tasks 11 | import { reload, serve } from './server'; 12 | import { styles } from './styles'; 13 | import { scripts } from './scripts'; 14 | import { templates } from './templates'; 15 | import { assets } from './assets'; 16 | import { copy } from './copy'; 17 | 18 | // Config 19 | import { paths } from "../config"; 20 | 21 | function watchFiles() { 22 | gulp.watch([paths.styles.watch, paths.styles.modules], styles); 23 | gulp.watch([paths.scripts.watch, paths.scripts.modules], series(scripts, reload)); 24 | gulp.watch([paths.templates.watch, paths.templates.modules], series(templates, reload)); 25 | gulp.watch(paths.assets.src, series(assets, reload)); 26 | gulp.watch(paths.copy.src, series(copy, reload)); 27 | } 28 | 29 | export const watch = series( 30 | serve, 31 | watchFiles 32 | ); 33 | -------------------------------------------------------------------------------- /gulpfile.babel.js/util/env.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @title Environments 3 | */ 4 | 5 | export const NODE_ENV = process.env.NODE_ENV ? "production" : "development"; 6 | export const isDev = process.NODE_ENV === "development"; 7 | export const isProd = process.env.NODE_ENV === 'production'; 8 | -------------------------------------------------------------------------------- /gulpfile.babel.js/util/errorHandler.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @title Error Handler 3 | */ 4 | 5 | import notifier from "node-notifier"; 6 | 7 | function errorHandler(error) { 8 | notifier.notify({ 9 | title: 'Gulp Error', 10 | message: error.message, 11 | timeout: 3 12 | }); 13 | console.error('\x1b[31m', error.message ,'\x1b[0m'); 14 | this.emit('end'); 15 | } 16 | 17 | export default errorHandler; 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hybrid-utility-itcss", 3 | "version": "1.0.0", 4 | "description": "Hybrid Utility ITCSS - Front-end boilerplate | ITCSS Architecture + CSS Utilities + Gulp 4 + Webpack 4 + Babel + BrowserSync + Twig.js", 5 | "main": "index.js", 6 | "devDependencies": { 7 | "@babel/core": "^7.5.5", 8 | "@babel/preset-env": "^7.5.5", 9 | "@babel/register": "^7.5.5", 10 | "autoprefixer": "^9.6.1", 11 | "babel-loader": "^8.0.6", 12 | "browser-sync": "^2.26.7", 13 | "cross-env": "^5.2.0", 14 | "css-loader": "^3.2.0", 15 | "del": "^5.1.0", 16 | "gulp": "^4.0.2", 17 | "gulp-babel": "^8.0.0", 18 | "gulp-changed": "^4.0.1", 19 | "gulp-eslint": "^6.0.0", 20 | "gulp-gh-pages": "^0.5.4", 21 | "gulp-if": "^3.0.0", 22 | "gulp-jsbeautifier": "^3.0.1", 23 | "gulp-plumber": "^1.2.1", 24 | "gulp-postcss": "^8.0.0", 25 | "gulp-sass": "^4.0.2", 26 | "gulp-sass-glob": "^1.1.0", 27 | "gulp-sourcemaps": "^2.6.5", 28 | "gulp-stylelint": "^9.0.0", 29 | "gulp-twig": "^1.2.0", 30 | "node-notifier": "^5.4.3", 31 | "sass-loader": "^7.3.1", 32 | "style-loader": "^1.0.0", 33 | "stylelint": "^10.1.0", 34 | "stylelint-config-recommended-scss": "^3.3.0", 35 | "stylelint-config-standard": "^18.3.0", 36 | "stylelint-order": "^3.0.1", 37 | "stylelint-scss": "^3.9.4", 38 | "webpack": "^4.39.2", 39 | "webpack-notifier": "^1.8.0", 40 | "webpack-stream": "^5.2.1" 41 | }, 42 | "engines": { 43 | "node": ">=8.16.0" 44 | }, 45 | "scripts": { 46 | "start": "cross-env NODE_ENV=development gulp", 47 | "watch": "cross-env NODE_ENV=development gulp watch", 48 | "build": "cross-env NODE_ENV=production gulp build", 49 | "deploy": "cross-env NODE_ENV=production gulp deploy" 50 | }, 51 | "repository": { 52 | "type": "git", 53 | "url": "git+https://github.com/tomaszbujnowicz/hybrid-utility-itcss.git" 54 | }, 55 | "keywords": [ 56 | "utility css", 57 | "itcss", 58 | "gulp", 59 | "gulp 4", 60 | "webpack", 61 | "webpack 4", 62 | "babel", 63 | "browsersync", 64 | "twig", 65 | "css architecture", 66 | "sass", 67 | "frontend", 68 | "frontend boilerplate", 69 | "frontend starter" 70 | ], 71 | "author": { 72 | "name": "Tomasz Bujnowicz", 73 | "email": "hi@tomaszbujnowicz.com", 74 | "url": "https://www.tomaszbujnowicz.com" 75 | }, 76 | "license": "MIT", 77 | "bugs": { 78 | "url": "https://github.com/tomaszbujnowicz/hybrid-utility-itcss/issues" 79 | }, 80 | "homepage": "https://github.com/tomaszbujnowicz/hybrid-utility-itcss#readme" 81 | } 82 | -------------------------------------------------------------------------------- /src/assets/fonts/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomaszbujnowicz/hybrid-utility-itcss/f8fe3ad673c18850bb5973c6f82df110aa1ac405/src/assets/fonts/.gitkeep -------------------------------------------------------------------------------- /src/assets/img/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomaszbujnowicz/hybrid-utility-itcss/f8fe3ad673c18850bb5973c6f82df110aa1ac405/src/assets/img/.gitkeep -------------------------------------------------------------------------------- /src/robots.txt: -------------------------------------------------------------------------------- 1 | # www.robotstxt.org/ 2 | 3 | # Allow crawling of all content 4 | User-agent: * 5 | Disallow: 6 | -------------------------------------------------------------------------------- /src/scripts/app.js: -------------------------------------------------------------------------------- 1 | /** 2 | * App 3 | */ 4 | 5 | import 'Utils/closest.polyfill.js'; 6 | import 'Utils/matches.polyfill.js'; 7 | 8 | import navbar from 'Components/navbar'; 9 | 10 | document.addEventListener('DOMContentLoaded', function() { 11 | navbar(); 12 | }); 13 | -------------------------------------------------------------------------------- /src/scripts/components/navbar.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Navbar 3 | */ 4 | 5 | export default function() { 6 | 7 | const navbar = document.querySelector('[data-component="navbar"]'); 8 | 9 | // When navbar exists 10 | if (navbar) { 11 | 12 | // Show an overlay on the navbar toggler click 13 | document.addEventListener('click', function (event) { 14 | 15 | // If the clicked element doesn't have the right selector, bail 16 | if (!event.target.closest('[data-js="navbar-toggler"]')) return; 17 | 18 | // Don't follow the link 19 | event.preventDefault(); 20 | 21 | // Toggle the body class 22 | document.body.classList.toggle('navbar--opened'); 23 | 24 | }, false); 25 | 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/scripts/utils/closest.polyfill.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Element.closest() polyfill 3 | * https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Polyfill 4 | */ 5 | 6 | if (!Element.prototype.closest) { 7 | Element.prototype.closest = function(s) { 8 | var el = this; 9 | 10 | do { 11 | if (el.matches(s)) return el; 12 | el = el.parentElement || el.parentNode; 13 | } while (el !== null && el.nodeType === 1); 14 | return null; 15 | }; 16 | } 17 | -------------------------------------------------------------------------------- /src/scripts/utils/matches.polyfill.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Element.matches() polyfill (simple version) 3 | * https://developer.mozilla.org/en-US/docs/Web/API/Element/matches#Polyfill 4 | */ 5 | 6 | if (!Element.prototype.matches) { 7 | Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector; 8 | } 9 | -------------------------------------------------------------------------------- /src/styles/1-settings/_breakpoints.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Breakpoints 3 | */ 4 | 5 | // Define media query breakpoints 6 | $grid-breakpoints: ( 7 | xs: 0, 8 | sm: 576px, 9 | md: 768px, 10 | lg: 992px, 11 | xl: 1200px, 12 | xxl: 1680px 13 | ) !default; 14 | 15 | // Define the maximum width of .container for different breakpoints. 16 | $container-max-widths: ( 17 | sm: 540px, 18 | md: 720px, 19 | lg: 960px, 20 | xl: 1140px, 21 | xxl: 1440px 22 | ) !default; 23 | -------------------------------------------------------------------------------- /src/styles/1-settings/_colors.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Colors 3 | */ 4 | 5 | $color-base: #4a5568 !default; 6 | $color-primary: #007bff !default; 7 | $color-secondary: #7f19e6 !default; 8 | $color-white: #fff !default; 9 | $color-light: #f2f2f2 !default; 10 | $color-dark: #2d3748 !default; 11 | $color-black: #000 !default; 12 | $color-success: #00b300 !default; 13 | $color-error: #c00 !default; 14 | 15 | // Used for generating CSS utility classes 16 | $colors: ( 17 | 'base': $color-base, 18 | 'primary': $color-primary, 19 | 'secondary': $color-secondary, 20 | 'white': $color-white, 21 | "light": $color-light, 22 | "dark": $color-dark, 23 | 'black': $color-black, 24 | 'success': $color-success, 25 | 'error': $color-error 26 | ) !default; 27 | 28 | // Links 29 | $color-link-color: #007bff !default; 30 | $color-link-color-hover: darken($color-link-color, 20%) !default; 31 | -------------------------------------------------------------------------------- /src/styles/1-settings/_global.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Global 3 | * 4 | * !default Flag 5 | * When building a library, a framework, a grid system or any piece of Sass 6 | * that is intended to be distributed and used by external developers, 7 | * all configuration variables should be defined with the !default flag 8 | * so they can be overwritten. 9 | */ 10 | 11 | // Transition 12 | $transition-base: all .2s ease-in-out !default; 13 | -------------------------------------------------------------------------------- /src/styles/1-settings/_spacing.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Spacing 3 | * Used for generating margin/padding CSS utility classes 4 | */ 5 | 6 | $spacer: 1rem !default; 7 | $spacers: ( 8 | 0: 0, 9 | 1: $spacer * .25, 10 | 2: $spacer * .5, 11 | 3: $spacer * .75, 12 | 4: $spacer * 1, 13 | 5: $spacer * 1.25, 14 | 6: $spacer * 1.5, 15 | 8: $spacer * 2, 16 | 12: $spacer * 3, 17 | auto: auto, 18 | ) !default; 19 | 20 | @function negativify-map($map) { 21 | $result: (); 22 | @each $key, $value in $map { 23 | @if $key != 0 { 24 | $result: map-merge($result, ($key: (-$value))); 25 | } 26 | } 27 | @return $result; 28 | } 29 | 30 | $negative-spacers: negativify-map($spacers) !default; 31 | -------------------------------------------------------------------------------- /src/styles/1-settings/_typography.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Typography 3 | */ 4 | 5 | // Font Family 6 | $font-family-base: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji" !default; 7 | $font-family-serif: Georgia, Cambria, "Times New Roman", Times, serif !default; 8 | $font-family-mono: Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace !default; 9 | $font-family-headings: $font-family-base; 10 | 11 | // Font Size 12 | $font-size-xs: .75rem !default; 13 | $font-size-sm: .875rem !default; 14 | $font-size-base: 1rem !default; 15 | $font-size-lg: 1.125rem !default; 16 | $font-size-xl: 1.25rem !default; 17 | 18 | // Font Weight 19 | $font-weight-hairline: 100 !default; 20 | $font-weight-thin: 200 !default; 21 | $font-weight-light: 300 !default; 22 | $font-weight-normal: 400 !default; 23 | $font-weight-medium: 500 !default; 24 | $font-weight-semibold: 600 !default; 25 | $font-weight-bold: 700 !default; 26 | $font-weight-extrabold: 800 !default; 27 | $font-weight-black: 900 !default; 28 | 29 | // Line Height 30 | $line-height-none: 1 !default; 31 | $line-height-xs: 1.25 !default; 32 | $line-height-sm: 1.375 !default; 33 | $line-height-base: 1.5 !default; 34 | $line-height-lg: 1.625 !default; 35 | $line-height-xl: 2 !default; 36 | 37 | // Headings 38 | $headings-margin-bottom: 1rem !default; 39 | $headings-font-family: $font-family-headings !default; 40 | $headings-font-weight: $font-weight-medium !default; 41 | $headings-letter-spacing: normal !default; 42 | $headings-line-height: 1.2 !default; 43 | $headings-color: inherit !default; 44 | $headings-text-transform: inherit !default; 45 | 46 | // Headings Responsive Size 47 | $h1-font-size: ( xs: 24px, sm: 26px, md: 28px, lg: 32px, xl: 36px, xxl: 40px ); 48 | $h2-font-size: ( xs: 22px, sm: 24px, md: 26px, lg: 28px, xl: 32px, xxl: 36px ); 49 | $h3-font-size: ( xs: 20px, sm: 22px, md: 24px, lg: 26px, xl: 28px, xxl: 32px ); 50 | $h4-font-size: ( xs: 18px, sm: 20px, md: 22px, lg: 24px, xl: 26px, xxl: 30px ); 51 | $h5-font-size: ( xs: 16px, sm: 18px, md: 20px, lg: 22px, xl: 24px, xxl: 26px ); 52 | $h6-font-size: ( xs: 16px, sm: 16px, md: 16px, lg: 18px, xl: 20px, xxl: 20px ); 53 | 54 | // List 55 | $list-margin-bottom: 1rem !default; 56 | 57 | // Paragraph 58 | $paragraph-margin-bottom: 1rem !default; 59 | -------------------------------------------------------------------------------- /src/styles/1-settings/_utilities.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Utilities 3 | * 4 | * Based on https://github.com/twbs/bootstrap/blob/master/scss/_utilities.scss 5 | */ 6 | 7 | $use-utilities: true; 8 | 9 | $utilities: () !default; 10 | $utilities: map-merge( 11 | ( 12 | // Backgrounds 13 | "background-color": ( 14 | responsive: true, 15 | property: background-color, 16 | class: bg, 17 | values: $colors, 18 | ), 19 | "background-size": ( 20 | responsive: true, 21 | property: background-size, 22 | class: bg, 23 | values: auto cover contain 24 | ), 25 | // Layout 26 | "display": ( 27 | responsive: true, 28 | property: display, 29 | class: no, 30 | values: ( 31 | hidden: none, 32 | inline: inline, 33 | inline-block: inline-block, 34 | block: block, 35 | table: table, 36 | table-row: table-row, 37 | table-cell: table-cell, 38 | flex: flex, 39 | inline-flex: inline-flex 40 | ) 41 | ), 42 | "position": ( 43 | responsive: true, 44 | property: position, 45 | class: no, 46 | values: static relative absolute fixed sticky 47 | ), 48 | "top": ( 49 | responsive: true, 50 | property: top, 51 | values: auto 0 52 | ), 53 | "right": ( 54 | responsive: true, 55 | property: right, 56 | values: auto 0 57 | ), 58 | "bottom": ( 59 | responsive: true, 60 | property: bottom, 61 | values: auto 0 62 | ), 63 | "left": ( 64 | property: left, 65 | values: auto 0 66 | ), 67 | "width": ( 68 | responsive: true, 69 | property: width, 70 | class: w, 71 | values: ( 72 | 0: 0, 73 | '1\\/2': 50%, 74 | '1\\/3': 33.333333%, 75 | '2\\/3': 66.666667%, 76 | '1\\/4': 25%, 77 | '2\\/4': 50%, 78 | '3\\/4': 75%, 79 | '1\\/5': 20%, 80 | '2\\/5': 40%, 81 | '3\\/5': 60%, 82 | '4\\/5': 80%, 83 | '1\\/6': 16.666667%, 84 | '2\\/6': 33.333333%, 85 | '3\\/6': 50%, 86 | '4\\/6': 66.666667%, 87 | '5\\/6': 83.333333%, 88 | // '1\\/12': 8.333333%, 89 | // '2\\/12': 16.666667%, 90 | // '3\\/12': 25%, 91 | // '4\\/12': 33.333333%, 92 | // '5\\/12': 41.666667%, 93 | // '6\\/12': 50%, 94 | // '7\\/12': 58.333333%, 95 | // '8\\/12': 66.666667%, 96 | // '9\\/12': 75%, 97 | // '10\\/12': 83.333333%, 98 | // '11\\/12': 91.666667%, 99 | 'full': 100%, 100 | 'w-screen': 100vw, 101 | 'auto': auto 102 | ) 103 | ), 104 | // Typography 105 | "color": ( 106 | responsive: true, 107 | property: color, 108 | class: text, 109 | values: $colors, 110 | ), 111 | "font-family": ( 112 | responsive: true, 113 | property: font-family, 114 | values: ( 115 | base: $font-family-base, 116 | serif: $font-family-serif, 117 | mono: $font-family-mono, 118 | headings: $font-family-headings, 119 | ) 120 | ), 121 | "font-size": ( 122 | responsive: true, 123 | property: font-size, 124 | values: ( 125 | xs: $font-size-xs, 126 | sm: $font-size-sm, 127 | base: $font-size-base, 128 | lg: $font-size-lg, 129 | xl: $font-size-xl, 130 | ) 131 | ), 132 | "font-style": ( 133 | responsive: true, 134 | property: font-style, 135 | class: no, 136 | values: ( 137 | italic: italic, 138 | non-italic: normal 139 | ) 140 | ), 141 | "font-weight": ( 142 | responsive: true, 143 | property: font-weight, 144 | values: ( 145 | hairline: $font-weight-hairline, 146 | thin: $font-weight-thin, 147 | light: $font-weight-light, 148 | normal: $font-weight-normal, 149 | medium: $font-weight-medium, 150 | semibold: $font-weight-semibold, 151 | bold: $font-weight-bold, 152 | extrabold: $font-weight-extrabold, 153 | 'black': $font-weight-black 154 | ) 155 | ), 156 | "line-height": ( 157 | responsive: true, 158 | property: line-height, 159 | values: ( 160 | none: $line-height-none, 161 | xs: $line-height-xs, 162 | sm: $line-height-sm, 163 | base: $line-height-base, 164 | lg: $line-height-lg, 165 | xl: $line-height-xl, 166 | ) 167 | ), 168 | "list-style-type": ( 169 | responsive: true, 170 | property: list-style-type, 171 | class: no, 172 | values: ( 173 | list-none: none, 174 | list-disc: disc, 175 | list-decimal: decimal 176 | ) 177 | ), 178 | "list-style-position": ( 179 | responsive: true, 180 | property: list-style-position, 181 | class: no, 182 | values: ( 183 | list-inside: inside, 184 | list-outside: outside 185 | ) 186 | ), 187 | "text-align": ( 188 | responsive: true, 189 | property: text-align, 190 | class: text, 191 | values: left right center justify 192 | ), 193 | "text-decoration": ( 194 | responsive: true, 195 | property: text-decoration, 196 | class: no, 197 | values: ( 198 | no-underline: none, 199 | underline: underline, 200 | line-through: line-through 201 | ) 202 | ), 203 | "text-transform": ( 204 | responsive: true, 205 | property: text-transform, 206 | class: no, 207 | values: lowercase uppercase capitalize 208 | ), 209 | // Flexbox 210 | "align-content": ( 211 | responsive: true, 212 | property: align-content, 213 | class: no, 214 | values: ( 215 | content-start: flex-start, 216 | content-end: flex-end, 217 | content-center: center, 218 | content-between: space-between, 219 | content-around: space-around, 220 | content-stretch: stretch, 221 | ) 222 | ), 223 | "align-items": ( 224 | responsive: true, 225 | property: align-items, 226 | class: no, 227 | values: ( 228 | items-start: flex-start, 229 | items-end: flex-end, 230 | items-center: center, 231 | items-baseline: baseline, 232 | items-stretch: stretch, 233 | ) 234 | ), 235 | "align-self": ( 236 | responsive: true, 237 | property: align-self, 238 | class: no, 239 | values: ( 240 | self-auto: auto, 241 | self-start: flex-start, 242 | self-end: flex-end, 243 | self-center: center, 244 | self-baseline: baseline, 245 | self-stretch: stretch, 246 | ) 247 | ), 248 | "flex": ( 249 | responsive: true, 250 | property: flex, 251 | values: (inital: 0 1 auto, 1: 1 1 0%, auto: 1 1 auto, none: none) 252 | ), 253 | "flex-direction": ( 254 | responsive: true, 255 | property: flex-direction, 256 | class: flex, 257 | values: row column row-reverse column-reverse 258 | ), 259 | "flex-grow": ( 260 | responsive: true, 261 | property: flex-grow, 262 | class: flex, 263 | values: ( 264 | grow: 0, 265 | grow-1: 1, 266 | ) 267 | ), 268 | "flex-shrink": ( 269 | responsive: true, 270 | property: flex-shrink, 271 | class: flex, 272 | values: ( 273 | shrink: 0, 274 | shrink-1: 1, 275 | ) 276 | ), 277 | "flex-wrap": ( 278 | responsive: true, 279 | property: flex-wrap, 280 | class: flex, 281 | values: wrap nowrap wrap-reverse 282 | ), 283 | "justify-content": ( 284 | responsive: true, 285 | property: justify-content, 286 | class: no, 287 | values: ( 288 | justify-start: flex-start, 289 | justify-end: flex-end, 290 | justify-center: center, 291 | justify-between: space-between, 292 | justify-around: space-around, 293 | ) 294 | ), 295 | "order": ( 296 | responsive: true, 297 | property: order, 298 | values: ( 299 | first: -9999, 300 | none: 0, 301 | 1: 1, 302 | 2: 2, 303 | 3: 3, 304 | 4: 4, 305 | 5: 5, 306 | last: 9999, 307 | ), 308 | ), 309 | // Spacing - Margin 310 | "margin": ( 311 | responsive: true, 312 | property: margin, 313 | class: m, 314 | values: $spacers 315 | ), 316 | "margin-x": ( 317 | responsive: true, 318 | property: margin-right margin-left, 319 | class: mx, 320 | values: $spacers 321 | ), 322 | "margin-y": ( 323 | responsive: true, 324 | property: margin-top margin-bottom, 325 | class: my, 326 | values: $spacers 327 | ), 328 | "margin-top": ( 329 | responsive: true, 330 | property: margin-top, 331 | class: mt, 332 | values: $spacers 333 | ), 334 | "margin-right": ( 335 | responsive: true, 336 | property: margin-right, 337 | class: mr, 338 | values: $spacers 339 | ), 340 | "margin-bottom": ( 341 | responsive: true, 342 | property: margin-bottom, 343 | class: mb, 344 | values: $spacers 345 | ), 346 | "margin-left": ( 347 | responsive: true, 348 | property: margin-left, 349 | class: ml, 350 | values: $spacers 351 | ), 352 | // Spacing - Negative Margin 353 | "negative-margin": ( 354 | responsive: true, 355 | property: margin, 356 | class: -m, 357 | values: $negative-spacers 358 | ), 359 | "negative-margin-x": ( 360 | responsive: true, 361 | property: margin-right margin-left, 362 | class: -mx, 363 | values: $negative-spacers 364 | ), 365 | "negative-margin-y": ( 366 | responsive: true, 367 | property: margin-top margin-bottom, 368 | class: -my, 369 | values: $negative-spacers 370 | ), 371 | "negative-margin-top": ( 372 | responsive: true, 373 | property: margin-top, 374 | class: -mt, 375 | values: $negative-spacers 376 | ), 377 | "negative-margin-right": ( 378 | responsive: true, 379 | property: margin-right, 380 | class: -mr, 381 | values: $negative-spacers 382 | ), 383 | "negative-margin-bottom": ( 384 | responsive: true, 385 | property: margin-bottom, 386 | class: -mb, 387 | values: $negative-spacers 388 | ), 389 | "negative-margin-left": ( 390 | responsive: true, 391 | property: margin-left, 392 | class: -ml, 393 | values: $negative-spacers 394 | ), 395 | // Spacing - Padding 396 | "padding": ( 397 | responsive: true, 398 | property: padding, 399 | class: p, 400 | values: $spacers 401 | ), 402 | "padding-x": ( 403 | responsive: true, 404 | property: padding-right padding-left, 405 | class: px, 406 | values: $spacers 407 | ), 408 | "padding-y": ( 409 | responsive: true, 410 | property: padding-top padding-bottom, 411 | class: py, 412 | values: $spacers 413 | ), 414 | "padding-top": ( 415 | responsive: true, 416 | property: padding-top, 417 | class: pt, 418 | values: $spacers 419 | ), 420 | "padding-right": ( 421 | responsive: true, 422 | property: padding-right, 423 | class: pr, 424 | values: $spacers 425 | ), 426 | "padding-bottom": ( 427 | responsive: true, 428 | property: padding-bottom, 429 | class: pb, 430 | values: $spacers 431 | ), 432 | "padding-left": ( 433 | responsive: true, 434 | property: padding-left, 435 | class: pl, 436 | values: $spacers 437 | ), 438 | ), 439 | $utilities 440 | ); 441 | 442 | // Disable utilities that we don't need in order to reduce css file size 443 | // Uncomment utiltiy to remove that from CSS 444 | 445 | $utilities: map-remove( 446 | $utilities, 447 | // "background-color", 448 | // "background-size", 449 | // "display", 450 | // "position", 451 | // "top", 452 | // "right", 453 | // "bottom", 454 | // "left", 455 | // "width", 456 | // "color", 457 | // "font-family", 458 | // "font-size", 459 | // "font-weight", 460 | // "line-height", 461 | // "list-style-type", 462 | // "list-style-position", 463 | // "text-align", 464 | // "text-decoration", 465 | // "text-transform", 466 | // "align-content", 467 | // "align-items", 468 | // "align-self", 469 | // "flex", 470 | // "flex-direction", 471 | // "flex-grow", 472 | // "flex-shrink", 473 | // "flex-wrap", 474 | // "justify-content", 475 | // "order", 476 | // "margin", 477 | // "margin-x", 478 | // "margin-y", 479 | // "margin-top", 480 | // "margin-right", 481 | // "margin-bottom", 482 | // "margin-left", 483 | // "negative-margin", 484 | // "negative-margin-x", 485 | // "negative-margin-y", 486 | // "negative-margin-top", 487 | // "negative-margin-right", 488 | // "negative-margin-bottom", 489 | // "negative-margin-left", 490 | // "padding", 491 | // "padding-x", 492 | // "padding-y", 493 | // "padding-top", 494 | // "padding-right", 495 | // "padding-bottom", 496 | // "padding-left" 497 | ); 498 | 499 | // Ratio 500 | $ratios: ( 501 | "16-9": ( 502 | x: 16, 503 | y: 9 504 | ), 505 | "3-4": ( 506 | x: 3, 507 | y: 4 508 | ), 509 | "4-3": ( 510 | x: 4, 511 | y: 3 512 | ), 513 | ) !default; 514 | -------------------------------------------------------------------------------- /src/styles/2-tools/_breakpoints.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Breakpoints 3 | * 4 | * Generate media queries breakpoints 5 | * Based on https://github.com/twbs/bootstrap/blob/master/scss/mixins/_breakpoints.scss 6 | */ 7 | 8 | // Breakpoint viewport sizes and media queries. 9 | // 10 | // Breakpoints are defined as a map of (name: minimum width), order from small to large: 11 | // 12 | // (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px) 13 | // 14 | // The map defined in the `$grid-breakpoints` global variable is used as the `$breakpoints` argument by default. 15 | 16 | // Name of the next breakpoint, or null for the last breakpoint. 17 | // 18 | // >> breakpoint-next(sm) 19 | // md 20 | // >> breakpoint-next(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px)) 21 | // md 22 | // >> breakpoint-next(sm, $breakpoint-names: (xs sm md lg xl)) 23 | // md 24 | @function breakpoint-next($name, $breakpoints: $grid-breakpoints, $breakpoint-names: map-keys($breakpoints)) { 25 | $n: index($breakpoint-names, $name); 26 | @if not $n { 27 | @error "breakpoint `#{$name}` not found in `#{$breakpoints}`"; 28 | } 29 | @return if($n < length($breakpoint-names), nth($breakpoint-names, $n + 1), null); 30 | } 31 | 32 | // Minimum breakpoint width. Null for the smallest (first) breakpoint. 33 | // 34 | // >> breakpoint-min(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px)) 35 | // 576px 36 | @function breakpoint-min($name, $breakpoints: $grid-breakpoints) { 37 | $min: map-get($breakpoints, $name); 38 | @return if($min != 0, $min, null); 39 | } 40 | 41 | // Maximum breakpoint width. Null for the largest (last) breakpoint. 42 | // The maximum value is calculated as the minimum of the next one less 0.02px 43 | // to work around the limitations of `min-` and `max-` prefixes and viewports with fractional widths. 44 | // See https://www.w3.org/TR/mediaqueries-4/#mq-min-max 45 | // Uses 0.02px rather than 0.01px to work around a current rounding bug in Safari. 46 | // See https://bugs.webkit.org/show_bug.cgi?id=178261 47 | // 48 | // >> breakpoint-max(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px)) 49 | // 767.98px 50 | @function breakpoint-max($name, $breakpoints: $grid-breakpoints) { 51 | $next: breakpoint-next($name, $breakpoints); 52 | @return if($next, breakpoint-min($next, $breakpoints) - .02, null); 53 | } 54 | 55 | // Returns a blank string if smallest breakpoint, otherwise returns the name with a dash in front. 56 | // Useful for making responsive utilities. 57 | // 58 | // >> breakpoint-infix(xs, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px)) 59 | // "" (Returns a blank string) 60 | // >> breakpoint-infix(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px)) 61 | // "-sm" 62 | @function breakpoint-infix($name, $breakpoints: $grid-breakpoints) { 63 | @return if(breakpoint-min($name, $breakpoints) == null, "", "#{$name}\\:"); 64 | } 65 | 66 | // Media of at least the minimum breakpoint width. No query for the smallest breakpoint. 67 | // Makes the @content apply to the given breakpoint and wider. 68 | @mixin media-breakpoint-up($name, $breakpoints: $grid-breakpoints) { 69 | $min: breakpoint-min($name, $breakpoints); 70 | @if $min { 71 | @media (min-width: $min) { 72 | @content; 73 | } 74 | } @else { 75 | @content; 76 | } 77 | } 78 | 79 | // Media of at most the maximum breakpoint width. No query for the largest breakpoint. 80 | // Makes the @content apply to the given breakpoint and narrower. 81 | @mixin media-breakpoint-down($name, $breakpoints: $grid-breakpoints) { 82 | $max: breakpoint-max($name, $breakpoints); 83 | @if $max { 84 | @media (max-width: $max) { 85 | @content; 86 | } 87 | } @else { 88 | @content; 89 | } 90 | } 91 | 92 | // Media that spans multiple breakpoint widths. 93 | // Makes the @content apply between the min and max breakpoints 94 | @mixin media-breakpoint-between($lower, $upper, $breakpoints: $grid-breakpoints) { 95 | $min: breakpoint-min($lower, $breakpoints); 96 | $max: breakpoint-max($upper, $breakpoints); 97 | 98 | @if $min != null and $max != null { 99 | @media (min-width: $min) and (max-width: $max) { 100 | @content; 101 | } 102 | } @else if $max == null { 103 | @include media-breakpoint-up($lower, $breakpoints) { 104 | @content; 105 | } 106 | } @else if $min == null { 107 | @include media-breakpoint-down($upper, $breakpoints) { 108 | @content; 109 | } 110 | } 111 | } 112 | 113 | // Media between the breakpoint's minimum and maximum widths. 114 | // No minimum for the smallest breakpoint, and no maximum for the largest one. 115 | // Makes the @content apply only to the given breakpoint, not viewports any wider or narrower. 116 | @mixin media-breakpoint-only($name, $breakpoints: $grid-breakpoints) { 117 | $min: breakpoint-min($name, $breakpoints); 118 | $max: breakpoint-max($name, $breakpoints); 119 | 120 | @if $min != null and $max != null { 121 | @media (min-width: $min) and (max-width: $max) { 122 | @content; 123 | } 124 | } @else if $max == null { 125 | @include media-breakpoint-up($name, $breakpoints) { 126 | @content; 127 | } 128 | } @else if $min == null { 129 | @include media-breakpoint-down($name, $breakpoints) { 130 | @content; 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/styles/2-tools/_generate-utility.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Utility generator 3 | */ 4 | 5 | @mixin generate-utility($utility, $infix) { 6 | $values: map-get($utility, values); 7 | 8 | // If the values are a list or string, convert it into a map 9 | @if type-of($values) == "string" or type-of(nth($values, 1)) != "list" { 10 | $values: zip($values, $values); 11 | } 12 | 13 | @each $key, $value in $values { 14 | $properties: map-get($utility, property); 15 | 16 | // Multiple properties are possible, for example with vertical or horizontal margins or paddings 17 | @if type-of($properties) == "string" { 18 | $properties: append((), $properties); 19 | } 20 | 21 | // Use custom class if present 22 | $property-class: map-get($utility, class); 23 | $property-class: if($property-class, $property-class, nth($properties, 1)); 24 | 25 | // Don't prefix if value key is null (eg. with shadow class) 26 | $property-class-modifier: if($key, "-" + $key, ""); 27 | 28 | @if $property-class == no { 29 | $property-class-modifier: $key; 30 | $property-class: ''; 31 | } 32 | 33 | .#{$infix + $property-class + $property-class-modifier} { 34 | @each $property in $properties { 35 | #{$property}: $value; 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/styles/2-tools/_make-responsive.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Make Responsive 3 | * 4 | * Responsive helper mixin 5 | * 6 | * Usage 7 | 8 | $body-font-size: ( 9 | xs: 10px, 10 | sm: 14px, 11 | md: 18px, 12 | lg: 22px, 13 | xl: 26px, 14 | xxl: 30px 15 | ); 16 | 17 | $body-padding-top: ( 18 | xs: 10px, 19 | sm: 20px, 20 | md: 30px, 21 | lg: 40px, 22 | xl: 50px, 23 | xxl: 60px 24 | ); 25 | 26 | body { 27 | @include make-responsive(font-size, $body-font-size); 28 | @include make-responsive(padding-top, $body-padding-top); 29 | } 30 | 31 | */ 32 | 33 | @mixin make-responsive($property, $map) { 34 | @each $breakpoint, $value in $map { 35 | @if $breakpoint == xs { 36 | #{$property}: $value; 37 | } 38 | @else { 39 | @include media-breakpoint-up($breakpoint) { 40 | #{$property}: $value; 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/styles/2-tools/_ratio.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Ratio 3 | * 4 | * If "true" is defined, we make target as pseudo :before element 5 | * 6 | * Usage: 7 | @include ratio(16,9); 8 | @include ratio(4,3); 9 | @include ratio(4,4, true); 10 | */ 11 | 12 | @mixin ratio($x,$y, $pseudo: false) { 13 | $padding: unquote(($y / $x) * 100 + '%'); 14 | background-size: cover; 15 | background-position: center; 16 | background-repeat: no-repeat; 17 | @if $pseudo { 18 | &:before { 19 | content: ""; 20 | display: block; 21 | width: 100%; 22 | padding-top: $padding; 23 | } 24 | } @else { 25 | padding-top: $padding; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/styles/3-generic/_font-face.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Font Face 3 | */ 4 | -------------------------------------------------------------------------------- /src/styles/3-generic/_print.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Print styles. 3 | * Taken from https://github.com/h5bp/html5-boilerplate 4 | */ 5 | 6 | @media print { 7 | *, 8 | *:before, 9 | *:after { 10 | background: transparent !important; 11 | color: #000 !important; /* Black prints faster */ 12 | -webkit-box-shadow: none !important; 13 | box-shadow: none !important; 14 | text-shadow: none !important; 15 | } 16 | 17 | a, 18 | a:visited { 19 | text-decoration: underline; 20 | } 21 | 22 | a[href]:after { 23 | content: " (" attr(href) ")"; 24 | } 25 | 26 | abbr[title]:after { 27 | content: " (" attr(title) ")"; 28 | } 29 | 30 | /* 31 | * Don't show links that are fragment identifiers, 32 | * or use the `javascript:` pseudo protocol 33 | */ 34 | 35 | a[href^="#"]:after, 36 | a[href^="javascript:"]:after { 37 | content: ""; 38 | } 39 | 40 | pre { 41 | white-space: pre-wrap !important; 42 | } 43 | pre, 44 | blockquote { 45 | border: 1px solid #999; 46 | page-break-inside: avoid; 47 | } 48 | 49 | /* 50 | * Printing Tables: 51 | * http://css-discuss.incutio.com/wiki/Printing_Tables 52 | */ 53 | 54 | thead { 55 | display: table-header-group; 56 | } 57 | 58 | tr, 59 | img { 60 | page-break-inside: avoid; 61 | } 62 | 63 | p, 64 | h2, 65 | h3 { 66 | orphans: 3; 67 | widows: 3; 68 | } 69 | 70 | h2, 71 | h3 { 72 | page-break-after: avoid; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/styles/3-generic/_sanitize.scss: -------------------------------------------------------------------------------- 1 | /* Document 2 | * ========================================================================== */ 3 | 4 | /** 5 | * Add border box sizing in all browsers (opinionated). 6 | */ 7 | 8 | *, 9 | ::before, 10 | ::after { 11 | box-sizing: border-box; 12 | } 13 | 14 | /** 15 | * 1. Add text decoration inheritance in all browsers (opinionated). 16 | * 2. Add vertical alignment inheritance in all browsers (opinionated). 17 | */ 18 | 19 | ::before, 20 | ::after { 21 | text-decoration: inherit; /* 1 */ 22 | vertical-align: inherit; /* 2 */ 23 | } 24 | 25 | /** 26 | * 1. Use the default cursor in all browsers (opinionated). 27 | * 2. Change the line height in all browsers (opinionated). 28 | * 3. Use a 4-space tab width in all browsers (opinionated). 29 | * 4. Remove the grey highlight on links in iOS (opinionated). 30 | * 5. Prevent adjustments of font size after orientation changes in 31 | * IE on Windows Phone and in iOS. 32 | * 6. Breaks words to prevent overflow in all browsers (opinionated). 33 | */ 34 | 35 | html { 36 | cursor: default; /* 1 */ 37 | line-height: 1.5; /* 2 */ 38 | -moz-tab-size: 4; /* 3 */ 39 | tab-size: 4; /* 3 */ 40 | -webkit-tap-highlight-color: transparent /* 4 */; 41 | -ms-text-size-adjust: 100%; /* 5 */ 42 | -webkit-text-size-adjust: 100%; /* 5 */ 43 | word-break: break-word; /* 6 */ 44 | } 45 | 46 | /* Sections 47 | * ========================================================================== */ 48 | 49 | /** 50 | * Remove the margin in all browsers (opinionated). 51 | */ 52 | 53 | body { 54 | margin: 0; 55 | } 56 | 57 | /** 58 | * Correct the font size and margin on `h1` elements within `section` and 59 | * `article` contexts in Chrome, Edge, Firefox, and Safari. 60 | */ 61 | 62 | h1 { 63 | font-size: 2em; 64 | margin: 0.67em 0; 65 | } 66 | 67 | /* Grouping content 68 | * ========================================================================== */ 69 | 70 | /** 71 | * Remove the margin on nested lists in Chrome, Edge, IE, and Safari. 72 | */ 73 | 74 | dl dl, 75 | dl ol, 76 | dl ul, 77 | ol dl, 78 | ul dl { 79 | margin: 0; 80 | } 81 | 82 | /** 83 | * Remove the margin on nested lists in Edge 18- and IE. 84 | */ 85 | 86 | ol ol, 87 | ol ul, 88 | ul ol, 89 | ul ul { 90 | margin: 0; 91 | } 92 | 93 | /** 94 | * 1. Add the correct sizing in Firefox. 95 | * 2. Show the overflow in Edge 18- and IE. 96 | */ 97 | 98 | hr { 99 | height: 0; /* 1 */ 100 | overflow: visible; /* 2 */ 101 | } 102 | 103 | /** 104 | * Add the correct display in IE. 105 | */ 106 | 107 | main { 108 | display: block; 109 | } 110 | 111 | /** 112 | * Remove the list style on navigation lists in all browsers (opinionated). 113 | */ 114 | 115 | nav ol, 116 | nav ul { 117 | list-style: none; 118 | padding: 0; 119 | } 120 | 121 | /** 122 | * 1. Correct the inheritance and scaling of font size in all browsers. 123 | * 2. Correct the odd `em` font sizing in all browsers. 124 | */ 125 | 126 | pre { 127 | font-family: monospace, monospace; /* 1 */ 128 | font-size: 1em; /* 2 */ 129 | } 130 | 131 | /* Text-level semantics 132 | * ========================================================================== */ 133 | 134 | /** 135 | * Remove the gray background on active links in IE 10. 136 | */ 137 | 138 | a { 139 | background-color: transparent; 140 | } 141 | 142 | /** 143 | * Add the correct text decoration in Edge 18-, IE, and Safari. 144 | */ 145 | 146 | abbr[title] { 147 | text-decoration: underline; 148 | text-decoration: underline dotted; 149 | } 150 | 151 | /** 152 | * Add the correct font weight in Chrome, Edge, and Safari. 153 | */ 154 | 155 | b, 156 | strong { 157 | font-weight: bolder; 158 | } 159 | 160 | /** 161 | * 1. Correct the inheritance and scaling of font size in all browsers. 162 | * 2. Correct the odd `em` font sizing in all browsers. 163 | */ 164 | 165 | code, 166 | kbd, 167 | samp { 168 | font-family: monospace, monospace; /* 1 */ 169 | font-size: 1em; /* 2 */ 170 | } 171 | 172 | /** 173 | * Add the correct font size in all browsers. 174 | */ 175 | 176 | small { 177 | font-size: 80%; 178 | } 179 | 180 | /* Embedded content 181 | * ========================================================================== */ 182 | 183 | /* 184 | * Change the alignment on media elements in all browsers (opinionated). 185 | */ 186 | 187 | audio, 188 | canvas, 189 | iframe, 190 | img, 191 | svg, 192 | video { 193 | vertical-align: middle; 194 | } 195 | 196 | /** 197 | * Add the correct display in IE 9-. 198 | */ 199 | 200 | audio, 201 | video { 202 | display: inline-block; 203 | } 204 | 205 | /** 206 | * Add the correct display in iOS 4-7. 207 | */ 208 | 209 | audio:not([controls]) { 210 | display: none; 211 | height: 0; 212 | } 213 | 214 | /** 215 | * Remove the border on iframes in all browsers (opinionated). 216 | */ 217 | 218 | iframe { 219 | border-style: none; 220 | } 221 | 222 | /** 223 | * Remove the border on images within links in IE 10-. 224 | */ 225 | 226 | img { 227 | border-style: none; 228 | } 229 | 230 | /** 231 | * Change the fill color to match the text color in all browsers (opinionated). 232 | */ 233 | 234 | svg:not([fill]) { 235 | fill: currentColor; 236 | } 237 | 238 | /** 239 | * Hide the overflow in IE. 240 | */ 241 | 242 | svg:not(:root) { 243 | overflow: hidden; 244 | } 245 | 246 | /* Tabular data 247 | * ========================================================================== */ 248 | 249 | /** 250 | * Collapse border spacing in all browsers (opinionated). 251 | */ 252 | 253 | table { 254 | border-collapse: collapse; 255 | } 256 | 257 | /* Forms 258 | * ========================================================================== */ 259 | 260 | /** 261 | * Remove the margin on controls in Safari. 262 | */ 263 | 264 | button, 265 | input, 266 | select { 267 | margin: 0; 268 | } 269 | 270 | /** 271 | * 1. Show the overflow in IE. 272 | * 2. Remove the inheritance of text transform in Edge 18-, Firefox, and IE. 273 | */ 274 | 275 | button { 276 | overflow: visible; /* 1 */ 277 | text-transform: none; /* 2 */ 278 | } 279 | 280 | /** 281 | * Correct the inability to style buttons in iOS and Safari. 282 | */ 283 | 284 | button, 285 | [type="button"], 286 | [type="reset"], 287 | [type="submit"] { 288 | -webkit-appearance: button; 289 | } 290 | 291 | /** 292 | * 1. Change the inconsistent appearance in all browsers (opinionated). 293 | * 2. Correct the padding in Firefox. 294 | */ 295 | 296 | fieldset { 297 | border: 1px solid #a0a0a0; /* 1 */ 298 | padding: 0.35em 0.75em 0.625em; /* 2 */ 299 | } 300 | 301 | /** 302 | * Show the overflow in Edge 18- and IE. 303 | */ 304 | 305 | input { 306 | overflow: visible; 307 | } 308 | 309 | /** 310 | * 1. Correct the text wrapping in Edge 18- and IE. 311 | * 2. Correct the color inheritance from `fieldset` elements in IE. 312 | */ 313 | 314 | legend { 315 | color: inherit; /* 2 */ 316 | display: table; /* 1 */ 317 | max-width: 100%; /* 1 */ 318 | white-space: normal; /* 1 */ 319 | } 320 | 321 | /** 322 | * 1. Add the correct display in Edge 18- and IE. 323 | * 2. Add the correct vertical alignment in Chrome, Edge, and Firefox. 324 | */ 325 | 326 | progress { 327 | display: inline-block; /* 1 */ 328 | vertical-align: baseline; /* 2 */ 329 | } 330 | 331 | /** 332 | * Remove the inheritance of text transform in Firefox. 333 | */ 334 | 335 | select { 336 | text-transform: none; 337 | } 338 | 339 | /** 340 | * 1. Remove the margin in Firefox and Safari. 341 | * 2. Remove the default vertical scrollbar in IE. 342 | * 3. Change the resize direction in all browsers (opinionated). 343 | */ 344 | 345 | textarea { 346 | margin: 0; /* 1 */ 347 | overflow: auto; /* 2 */ 348 | resize: vertical; /* 3 */ 349 | } 350 | 351 | /** 352 | * Remove the padding in IE 10-. 353 | */ 354 | 355 | [type="checkbox"], 356 | [type="radio"] { 357 | padding: 0; 358 | } 359 | 360 | /** 361 | * 1. Correct the odd appearance in Chrome, Edge, and Safari. 362 | * 2. Correct the outline style in Safari. 363 | */ 364 | 365 | [type="search"] { 366 | -webkit-appearance: textfield; /* 1 */ 367 | outline-offset: -2px; /* 2 */ 368 | } 369 | 370 | /** 371 | * Correct the cursor style of increment and decrement buttons in Safari. 372 | */ 373 | 374 | ::-webkit-inner-spin-button, 375 | ::-webkit-outer-spin-button { 376 | height: auto; 377 | } 378 | 379 | /** 380 | * Correct the text style of placeholders in Chrome, Edge, and Safari. 381 | */ 382 | 383 | ::-webkit-input-placeholder { 384 | color: inherit; 385 | opacity: 0.54; 386 | } 387 | 388 | /** 389 | * Remove the inner padding in Chrome, Edge, and Safari on macOS. 390 | */ 391 | 392 | ::-webkit-search-decoration { 393 | -webkit-appearance: none; 394 | } 395 | 396 | /** 397 | * 1. Correct the inability to style upload buttons in iOS and Safari. 398 | * 2. Change font properties to `inherit` in Safari. 399 | */ 400 | 401 | ::-webkit-file-upload-button { 402 | -webkit-appearance: button; /* 1 */ 403 | font: inherit; /* 2 */ 404 | } 405 | 406 | /** 407 | * Remove the inner border and padding of focus outlines in Firefox. 408 | */ 409 | 410 | ::-moz-focus-inner { 411 | border-style: none; 412 | padding: 0; 413 | } 414 | 415 | /** 416 | * Restore the focus outline styles unset by the previous rule in Firefox. 417 | */ 418 | 419 | :-moz-focusring { 420 | outline: 1px dotted ButtonText; 421 | } 422 | 423 | /** 424 | * Remove the additional :invalid styles in Firefox. 425 | */ 426 | 427 | :-moz-ui-invalid { 428 | box-shadow: none; 429 | } 430 | 431 | /* Interactive 432 | * ========================================================================== */ 433 | 434 | /* 435 | * Add the correct display in Edge 18- and IE. 436 | */ 437 | 438 | details { 439 | display: block; 440 | } 441 | 442 | /* 443 | * Add the correct styles in Edge 18-, IE, and Safari. 444 | */ 445 | 446 | dialog { 447 | background-color: white; 448 | border: solid; 449 | color: black; 450 | display: block; 451 | height: -moz-fit-content; 452 | height: -webkit-fit-content; 453 | height: fit-content; 454 | left: 0; 455 | margin: auto; 456 | padding: 1em; 457 | position: absolute; 458 | right: 0; 459 | width: -moz-fit-content; 460 | width: -webkit-fit-content; 461 | width: fit-content; 462 | } 463 | 464 | dialog:not([open]) { 465 | display: none; 466 | } 467 | 468 | /* 469 | * Add the correct display in all browsers. 470 | */ 471 | 472 | summary { 473 | display: list-item; 474 | } 475 | 476 | /* Scripting 477 | * ========================================================================== */ 478 | 479 | /** 480 | * Add the correct display in IE 9-. 481 | */ 482 | 483 | canvas { 484 | display: inline-block; 485 | } 486 | 487 | /** 488 | * Add the correct display in IE. 489 | */ 490 | 491 | template { 492 | display: none; 493 | } 494 | 495 | /* User interaction 496 | * ========================================================================== */ 497 | 498 | /* 499 | * 1. Remove the tapping delay in IE 10. 500 | * 2. Remove the tapping delay on clickable elements 501 | in all browsers (opinionated). 502 | */ 503 | 504 | a, 505 | area, 506 | button, 507 | input, 508 | label, 509 | select, 510 | summary, 511 | textarea, 512 | [tabindex] { 513 | -ms-touch-action: manipulation; /* 1 */ 514 | touch-action: manipulation; /* 2 */ 515 | } 516 | 517 | /** 518 | * Add the correct display in IE 10-. 519 | */ 520 | 521 | [hidden] { 522 | display: none; 523 | } 524 | 525 | /* Accessibility 526 | * ========================================================================== */ 527 | 528 | /** 529 | * Change the cursor on busy elements in all browsers (opinionated). 530 | */ 531 | 532 | [aria-busy="true"] { 533 | cursor: progress; 534 | } 535 | 536 | /* 537 | * Change the cursor on control elements in all browsers (opinionated). 538 | */ 539 | 540 | [aria-controls] { 541 | cursor: pointer; 542 | } 543 | 544 | /* 545 | * Change the cursor on disabled, not-editable, or otherwise 546 | * inoperable elements in all browsers (opinionated). 547 | */ 548 | 549 | [aria-disabled="true"], 550 | [disabled] { 551 | cursor: not-allowed; 552 | } 553 | 554 | /* 555 | * Change the display on visually hidden accessible elements 556 | * in all browsers (opinionated). 557 | */ 558 | 559 | [aria-hidden="false"][hidden] { 560 | display: initial; 561 | } 562 | 563 | [aria-hidden="false"][hidden]:not(:focus) { 564 | clip: rect(0, 0, 0, 0); 565 | position: absolute; 566 | } 567 | -------------------------------------------------------------------------------- /src/styles/4-elements/_blockquote.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Blockquote 3 | */ 4 | 5 | blockquote { 6 | margin: 0; 7 | p { 8 | &:before { 9 | content: open-quote; 10 | } 11 | &:after { 12 | content: close-quote; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/styles/4-elements/_document.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Document defaults (html, body) 3 | */ 4 | 5 | html { 6 | font-family: $font-family-base; 7 | font-size: $font-size-base; 8 | color: $color-base; 9 | line-height: $line-height-base; 10 | -webkit-font-smoothing: antialiased; 11 | -moz-osx-font-smoothing: grayscale; 12 | text-rendering: optimizeLegibility; 13 | } 14 | -------------------------------------------------------------------------------- /src/styles/4-elements/_headings.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Headings 3 | */ 4 | 5 | h1, 6 | h2, 7 | h3, 8 | h4, 9 | h5, 10 | h6, 11 | .h1, 12 | .h2, 13 | .h3, 14 | .h4, 15 | .h5, 16 | .h6 { 17 | margin-top: 0; 18 | margin-bottom: $headings-margin-bottom; 19 | font-family: $headings-font-family; 20 | font-weight: $headings-font-weight; 21 | letter-spacing: $headings-letter-spacing; 22 | line-height: $headings-line-height; 23 | color: $headings-color; 24 | text-transform: $headings-text-transform; 25 | } 26 | 27 | h1, 28 | .h1 { 29 | @include make-responsive(font-size, $h1-font-size); 30 | } 31 | h2, 32 | .h2 { 33 | @include make-responsive(font-size, $h2-font-size); 34 | } 35 | h3, 36 | .h3 { 37 | @include make-responsive(font-size, $h3-font-size); 38 | } 39 | h4, 40 | .h4 { 41 | @include make-responsive(font-size, $h4-font-size); 42 | } 43 | h5, 44 | .h5 { 45 | @include make-responsive(font-size, $h5-font-size); 46 | } 47 | h6, 48 | .h6 { 49 | @include make-responsive(font-size, $h6-font-size); 50 | } 51 | -------------------------------------------------------------------------------- /src/styles/4-elements/_links.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Links 3 | */ 4 | 5 | a { 6 | color: $color-link-color; 7 | text-decoration: none; 8 | background-color: transparent; // Remove the gray background on active links in IE 10. 9 | -webkit-text-decoration-skip: objects; // Remove gaps in links underline in iOS 8+ and Safari 8+. 10 | &:hover { 11 | color: $color-link-color-hover; 12 | text-decoration: underline; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/styles/4-elements/_lists.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Lists 3 | */ 4 | 5 | ol, 6 | ul, 7 | dl { 8 | margin-top: 0; 9 | margin-bottom: $list-margin-bottom; 10 | } 11 | -------------------------------------------------------------------------------- /src/styles/4-elements/_media.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Media 3 | */ 4 | 5 | /** 6 | * Make replaced elements `display: block` by default as that's 7 | * the behavior you want almost all of the time. Inspired by 8 | * CSS Remedy, with `svg` added as well. 9 | * 10 | * https://github.com/mozdevs/cssremedy/issues/14 11 | */ 12 | 13 | img, 14 | svg, 15 | video, 16 | canvas, 17 | audio, 18 | iframe, 19 | embed, 20 | object { 21 | display: block; 22 | vertical-align: middle; 23 | } 24 | 25 | figure { 26 | margin: 0; 27 | } 28 | 29 | // Constrain images and videos to the parent width 30 | 31 | img, 32 | video { 33 | max-width: 100%; 34 | height: auto; 35 | } 36 | 37 | // If a `width` and/or `height` attribute have been explicitly defined, let’s not make the image fluid. 38 | 39 | img[width], 40 | img[height] { 41 | max-width: none; 42 | } 43 | -------------------------------------------------------------------------------- /src/styles/4-elements/_paragraphs.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Paragraph 3 | */ 4 | 5 | p { 6 | margin-top: 0; 7 | margin-bottom: $paragraph-margin-bottom; 8 | } 9 | -------------------------------------------------------------------------------- /src/styles/4-elements/_tables.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Tables 3 | */ 4 | 5 | table { 6 | width: 100%; 7 | border-spacing: 0; 8 | } 9 | th { 10 | text-align: inherit; 11 | } 12 | -------------------------------------------------------------------------------- /src/styles/5-objects/_container..scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Container 3 | */ 4 | 5 | .container, 6 | .container-fluid { 7 | width: 100%; 8 | margin-right: auto; 9 | margin-left: auto; 10 | } 11 | 12 | .container { 13 | @include make-responsive(max-width, $container-max-widths); 14 | } 15 | -------------------------------------------------------------------------------- /src/styles/6-components/_buttons.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Buttons 3 | */ 4 | 5 | $btn-color-bg: $color-primary !default; 6 | $btn-color-bg-hover: darken($color-primary, 10%) !default; 7 | 8 | $btn-color-text: white !default; 9 | $btn-color-text-hover: white !default; 10 | 11 | $btn-font-weight: inherit !default; 12 | $btn-font-size: 1rem !default; 13 | 14 | $btn-padding-x: .75rem !default; 15 | $btn-padding-y: .5rem !default; 16 | 17 | $btn-border-color: transparent !default; 18 | $btn-border-color-hover: transparent !default; 19 | $btn-border-width: 1px !default; 20 | $btn-border-radius: 4px !default; 21 | 22 | $btn-sm: .75 !default; 23 | $btn-lg: 1.25 !default; 24 | 25 | .btn { 26 | display: inline-block; 27 | padding: $btn-padding-y $btn-padding-x; 28 | border: $btn-border-width solid transparent; 29 | background-color: $btn-color-bg; 30 | color: $btn-color-text; 31 | vertical-align: middle; 32 | text-align: center; 33 | white-space: nowrap; 34 | font-size: $btn-font-size; 35 | font-weight: $btn-font-weight; 36 | line-height: $line-height-base; 37 | cursor: pointer; 38 | transition: $transition-base; 39 | user-select: none; 40 | text-decoration: none; 41 | border-radius: $btn-border-radius; 42 | 43 | &:hover, 44 | &:focus { 45 | text-decoration: none; 46 | } 47 | 48 | &:hover { 49 | background-color: $btn-color-bg-hover; 50 | color: $btn-color-text-hover; 51 | border-color: $btn-border-color-hover; 52 | } 53 | 54 | &:focus { 55 | outline: 0; 56 | } 57 | } 58 | 59 | // Size Variants 60 | .btn-sm { 61 | font-size: $btn-font-size * $btn-sm; 62 | padding: ($btn-padding-y * $btn-sm) ($btn-padding-x * $btn-sm); 63 | } 64 | .btn-lg { 65 | font-size: $btn-font-size * $btn-lg; 66 | padding: ($btn-padding-y * $btn-lg) ($btn-padding-x * $btn-lg); 67 | } 68 | 69 | // Block 70 | .btn-block { 71 | display: block; 72 | width: 100%; 73 | } 74 | 75 | // Disabled 76 | .btn:disabled { 77 | opacity: .65; 78 | pointer-events: none; 79 | } 80 | 81 | // Outline 82 | .btn-outline { 83 | border-color: $btn-color-bg; 84 | background-color: transparent; 85 | color: $btn-color-bg; 86 | &:hover { 87 | border-color: $btn-color-bg; 88 | background-color: $btn-color-bg; 89 | color: $btn-color-text-hover; 90 | } 91 | } 92 | 93 | // Link 94 | .btn-link { 95 | box-shadow: none; 96 | background-color: transparent; 97 | border-color: transparent; 98 | color: $color-primary; 99 | text-shadow: none; 100 | text-transform: none; 101 | 102 | &:hover { 103 | border-color: $btn-color-bg; 104 | background-color: transparent; 105 | color: $btn-color-bg-hover; 106 | } 107 | } 108 | 109 | // Colors 110 | .btn-primary { 111 | &.btn-link { 112 | color: $color-primary; 113 | &:hover { 114 | color: darken($color-primary, 10%); 115 | border-color: darken($color-primary, 10%); 116 | } 117 | } 118 | } 119 | .btn-secondary { 120 | background-color: $color-secondary; 121 | &:hover { 122 | background-color: darken($color-secondary, 10%); 123 | border-color: darken($color-secondary, 10%); 124 | } 125 | &.btn-outline { 126 | background-color: transparent; 127 | border-color: $color-secondary; 128 | color: $color-secondary; 129 | &:hover { 130 | background-color: darken($color-secondary, 10%); 131 | border-color: darken($color-secondary, 10%); 132 | color: $color-white; 133 | } 134 | } 135 | &.btn-link { 136 | background-color: transparent; 137 | color: $color-secondary; 138 | &:hover { 139 | color: darken($color-secondary, 10%); 140 | } 141 | } 142 | } 143 | .btn-success { 144 | background-color: $color-success; 145 | &:hover { 146 | background-color: darken($color-success, 10%); 147 | border-color: darken($color-success, 10%); 148 | } 149 | &.btn-outline { 150 | background-color: transparent; 151 | border-color: $color-success; 152 | color: $color-success; 153 | &:hover { 154 | background-color: darken($color-success, 10%); 155 | border-color: darken($color-success, 10%); 156 | color: $color-white; 157 | } 158 | } 159 | &.btn-link { 160 | background-color: transparent; 161 | color: $color-success; 162 | &:hover { 163 | color: darken($color-success, 10%); 164 | } 165 | } 166 | } 167 | .btn-error { 168 | background-color: $color-error; 169 | &:hover { 170 | background-color: darken($color-error, 10%); 171 | border-color: darken($color-error, 10%); 172 | } 173 | &.btn-outline { 174 | background-color: transparent; 175 | border-color: $color-error; 176 | color: $color-error; 177 | &:hover { 178 | background-color: darken($color-error, 10%); 179 | border-color: darken($color-error, 10%); 180 | color: $color-white; 181 | } 182 | } 183 | &.btn-link { 184 | background-color: transparent; 185 | color: $color-error; 186 | &:hover { 187 | color: darken($color-error, 10%); 188 | } 189 | } 190 | } 191 | .btn-white { 192 | background-color: $color-white; 193 | color: $color-black; 194 | &:hover { 195 | background-color: darken($color-black, 10%); 196 | border-color: darken($color-black, 10%); 197 | color: $color-white; 198 | } 199 | &.btn-outline { 200 | background-color: transparent; 201 | border-color: $color-white; 202 | color: $color-white; 203 | &:hover { 204 | background-color: darken($color-black, 10%); 205 | border-color: darken($color-black, 10%); 206 | color: $color-white; 207 | } 208 | } 209 | &.btn-link { 210 | background-color: transparent; 211 | color: $color-white; 212 | &:hover { 213 | color: $color-black; 214 | } 215 | } 216 | } 217 | .btn-black { 218 | background-color: $color-black; 219 | &:hover { 220 | background-color: lighten($color-black, 10%); 221 | border-color: lighten($color-black, 10%); 222 | } 223 | &.btn-outline { 224 | background-color: transparent; 225 | border-color: $color-black; 226 | color: $color-black; 227 | &:hover { 228 | background-color: lighten($color-black, 10%); 229 | border-color: lighten($color-black, 10%); 230 | color: $color-white; 231 | } 232 | } 233 | &.btn-link { 234 | background-color: transparent; 235 | color: $color-black; 236 | &:hover { 237 | color: lighten($color-black, 10%); 238 | } 239 | } 240 | } 241 | -------------------------------------------------------------------------------- /src/styles/7-modules/_navbar.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Navbar 3 | */ 4 | 5 | $navbar-height-desktop: 80px; 6 | $navbar-height-mobile: 50px; 7 | $navbar-color-bg: #fafafa; 8 | $navbar-color-link: $color-link-color; 9 | $navbar-color-link-hover: $color-link-color-hover; 10 | $navbar-size-toggler: 8px; 11 | 12 | .navbar { 13 | background-color: $navbar-color-bg; 14 | z-index: 100; 15 | } 16 | .navbar__wrapper { 17 | display: flex; 18 | align-items: center; 19 | } 20 | .navbar__brand { 21 | color: $navbar-color-link; 22 | &:hover { 23 | text-decoration: none; 24 | color: $navbar-color-link-hover; 25 | } 26 | } 27 | .navbar__toggler { 28 | display: none; 29 | &:focus { 30 | outline: none; 31 | } 32 | } 33 | .navbar__menu { 34 | display: flex; 35 | align-items: center; 36 | list-style: none; 37 | margin: 0; 38 | padding: 0; 39 | } 40 | .navbar__item { 41 | margin-bottom: 0; 42 | } 43 | .navbar__link { 44 | transition: $transition-base; 45 | color: $navbar-color-link; 46 | text-decoration: none; 47 | } 48 | .navbar__item--selected .navbar__link { 49 | color: $navbar-color-link-hover; 50 | } 51 | 52 | // Media: Small breakpoint and down 53 | @include media-breakpoint-down(sm) { 54 | .navbar__wrapper { 55 | height: $navbar-height-mobile; 56 | } 57 | .navbar__collapse, 58 | .navbar__toggler, 59 | .navbar__toggler-link { 60 | transition: $transition-base; 61 | } 62 | .navbar__collapse { 63 | opacity: 0; 64 | visibility: hidden; 65 | position: fixed; 66 | top: 0; 67 | left: 0; 68 | right: 0; 69 | bottom: 0; 70 | width: 100%; 71 | height: 100%; 72 | overflow-x: hidden; 73 | overflow-y: auto; 74 | pointer-events: auto; 75 | } 76 | .navbar__toggler { 77 | display: inline-block; 78 | position: relative; 79 | margin: 0; 80 | margin-left: auto; 81 | padding: 0; 82 | background: none; 83 | border: none; 84 | border-radius: 0; 85 | width: $navbar-size-toggler * 5; 86 | height: $navbar-size-toggler * 4; 87 | cursor: pointer; 88 | z-index: 110; 89 | } 90 | .navbar__toggler-line { 91 | display: block; 92 | position: absolute; 93 | top: $navbar-size-toggler; 94 | left: $navbar-size-toggler; 95 | background-color: black; 96 | height: 1px; 97 | width: $navbar-size-toggler * 3; 98 | &:nth-child(2) { 99 | top: $navbar-size-toggler * 2; 100 | } 101 | &:nth-child(3) { 102 | top: $navbar-size-toggler * 3; 103 | } 104 | } 105 | .navbar__menu { 106 | align-items: center; 107 | justify-content: center; 108 | flex-direction: column; 109 | min-height: 100vh; 110 | background-color: $navbar-color-bg; 111 | padding: 2rem 0; 112 | } 113 | .navbar__item:not(:last-child) { 114 | margin-bottom: 1rem; 115 | } 116 | body.navbar--opened { 117 | // Prevent vertical scrollbar when navbar is opened on smaller devices 118 | overflow: hidden; 119 | 120 | .navbar__collapse { 121 | visibility: visible; 122 | opacity: 1; 123 | } 124 | .navbar__toggler-line { 125 | &:nth-child(1) { 126 | top: $navbar-size-toggler * 2; 127 | transform: rotate(45deg); 128 | } 129 | &:nth-child(2) { 130 | opacity: 0; 131 | } 132 | &:nth-child(3) { 133 | top: $navbar-size-toggler * 2; 134 | transform: rotate(-45deg); 135 | } 136 | } 137 | .navbar__toggler { 138 | &:hover { 139 | transform: rotate(90deg); 140 | } 141 | } 142 | } 143 | } 144 | 145 | // Media: Medium breakpoint and up 146 | @include media-breakpoint-up(md) { 147 | .navbar__wrapper { 148 | height: $navbar-height-desktop; 149 | } 150 | .navbar__brand { 151 | margin-right: auto; 152 | } 153 | .navbar__menu { 154 | flex-direction: row; 155 | } 156 | .navbar__item:not(:last-child) { 157 | margin-right: 2rem; 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /src/styles/8-utilities/_ratio.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Ratio 3 | */ 4 | 5 | @each $key, $ratio in $ratios { 6 | .ratio-#{$key} { 7 | @include ratio(map-get($ratio, x), map-get($ratio, y)); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/styles/8-utilities/_utilities.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Utilities 3 | * 4 | * Generate utilities 5 | */ 6 | 7 | // Loop over each breakpoint 8 | @if $use-utilities { 9 | 10 | @each $breakpoint in map-keys($grid-breakpoints) { 11 | 12 | // Generate media query if needed 13 | @include media-breakpoint-up($breakpoint) { 14 | $infix: breakpoint-infix($breakpoint, $grid-breakpoints); 15 | 16 | // Loop over each utility property 17 | @each $key, $utility in $utilities { 18 | // The utility can be disabled with `false`, thus check if the utility is a map first 19 | // Only proceed if responsive media queries are enabled or if it's the base media query 20 | @if type-of($utility) == "map" and (map-get($utility, responsive) or $infix == "") { 21 | @include generate-utility($utility, $infix); 22 | } 23 | } 24 | } 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/styles/_shame.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Shame file 3 | * 4 | * This is a place for hacky, nasty code that should be replaced 5 | * and moved to the correct partial. Ideally, this is empty. 6 | */ 7 | -------------------------------------------------------------------------------- /src/styles/main.scss: -------------------------------------------------------------------------------- 1 | /*! 2 | * Project: Project Name 3 | * Author: Name 4 | * E-mail: E-mail 5 | * Website: 6 | */ 7 | 8 | /** 9 | * The structure is based on ITCSS with custom modifications. 10 | * 11 | * This is where all of the stylesheets are compiled. 12 | * They are processed in the order they are imported 13 | * to ensure the consistent increase of specificity. 14 | * 15 | * ITCSS Methodology: Inverted Triangle CSS 16 | * 17 | * **************** 1. Settings 18 | * ************** 2. Tools 19 | * ************ 3. Generic 20 | * ********** 4. Elements 21 | * ******** 5. Objects 22 | * ****** 6. Components 23 | * **** 7. Modules 24 | * ** 8. Utilities 25 | * 26 | * 1. Settings 27 | * Global configuration and variables. 28 | * Breakpoints, colors, spacing, utilities etc. 29 | * 30 | * 2. Tools 31 | * Functions and mixins. 32 | * 33 | * 3. Generic 34 | * Ground zero styles. No classes. 35 | * 36 | * 4. Elements 37 | * Unclassed (bare) HTML element. 38 | * H1, Ul, A etc. 39 | * 40 | * 5. Objects 41 | * Common non-cosmetic structural design patterns. 42 | * Containers, rows, grids, colums etc. 43 | * 44 | * 6. Components 45 | * Specific cosmetic elements of UI. 46 | * Buttons, forms etc. 47 | * 48 | * 7. Modules 49 | * Multi-part components. 50 | * Navbar, footer etc. 51 | * 52 | * 8. Utilities 53 | * Helpers and overrides. 54 | * 55 | * Shame 56 | * All the CSS, hacks and things we are not proud of. 57 | */ 58 | 59 | @import '1-settings/**/*.scss'; 60 | @import '2-tools/**/*.scss'; 61 | @import '3-generic/**/*.scss'; 62 | @import '4-elements/**/*.scss'; 63 | @import '5-objects/**/*.scss'; 64 | @import '6-components/**/*.scss'; 65 | @import '7-modules/**/*.scss'; 66 | @import '8-utilities/**/*.scss'; 67 | @import 'shame'; 68 | -------------------------------------------------------------------------------- /src/templates/components/footer.twig: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /src/templates/components/navbar.twig: -------------------------------------------------------------------------------- 1 | 29 | -------------------------------------------------------------------------------- /src/templates/layouts/default.twig: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | {{ head_title }} · Hybrid Utility ITCSS 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | {% block page %}{% endblock %} 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/templates/pages/404.twig: -------------------------------------------------------------------------------- 1 | {# taken from https://github.com/h5bp/html5-boilerplate/blob/master/src/404.html #} 2 | 3 | 4 | 5 | 6 | Page Not Found 7 | 8 | 45 | 46 | 47 |

Page Not Found

48 |

Sorry, but the page you were trying to view does not exist.

49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /src/templates/pages/index.twig: -------------------------------------------------------------------------------- 1 | {% extends '../layouts/default.twig' %} 2 | {% set head_title = 'Welcome' %} 3 | {% set body_class = 'bg-light' %} 4 | {% set menu_active = 'demo-page' %} 5 | 6 | {% block page %} 7 | 8 | 9 | 10 | 50 | 51 |
52 | 53 |
54 | 55 |
56 | 57 | 58 |
59 | 60 |
61 | 62 |
63 | 64 |

65 | Hybrid Utility ITCSS 66 |

67 |

68 | Front-end boilerplate / ITCSS Architecture / CSS Utilities 69 |

70 |

71 | Gulp / Webpack / Babel / Live Reload / Twig.js 72 |

73 |

74 | Based on best pieces from Bootstrap, Tailwind CSS and years of experience. 75 |

76 | 77 |
78 | 79 |
80 | 81 |
82 | 83 | 84 |
85 | 86 |
87 | 88 | 108 | 109 |
110 | 111 |

112 | Settings 113 |

114 | 115 |
116 | 117 | ITCSS Overview 118 | 119 | 167 |
168 | 169 |
170 | 171 | Breakpoints 172 | 173 | 243 |
244 | 245 |
246 | 247 | Colors 248 | 249 | 282 |
283 | 284 |
285 | 286 | Spacing 287 | 288 | 308 |
309 | 310 |
311 | 312 | Typography 313 | 314 | 374 |
375 | 376 |
377 | 378 | Utilities 379 | 380 | 431 |
432 | 433 |
434 | 435 |
436 | 437 |

438 | Backgrounds 439 |

440 | 441 |
442 | 443 | background-color 444 | 445 | 473 |
474 | 475 |
476 | 477 | background-size 478 | 479 | 494 |
495 | 496 |
497 | 498 |
499 | 500 |

501 | Layout 502 |

503 | 504 |
505 | 506 | container 507 | 508 | 557 |
558 | 559 |
560 | 561 | display 562 | 563 | 588 |
589 | 590 |
591 | 592 | position 593 | 594 | 615 |
616 | 617 |
618 | 619 | top-right-bottom-left 620 | 621 | 645 |
646 | 647 |
648 | 649 | width 650 | 651 | 682 |
683 | 684 |
685 | 686 |
687 | 688 |

689 | Typography 690 |

691 | 692 |
693 | 694 | color 695 | 696 | 724 |
725 | 726 |
727 | 728 | font-family 729 | 730 | 750 |
751 | 752 |
753 | 754 | font-size 755 | 756 | 777 |
778 | 779 |
780 | 781 | font-style 782 | 783 | 801 |
802 | 803 |
804 | 805 | font-weight 806 | 807 | 832 |
833 | 834 |
835 | 836 | line-height 837 | 838 | 859 |
860 | 861 |
862 | 863 | list-style-type 864 | 865 | 884 |
885 | 886 |
887 | 888 | list-style-position 889 | 890 | 908 |
909 | 910 |
911 | 912 | text-align 913 | 914 | 935 |
936 | 937 |
938 | 939 | text-decoration 940 | 941 | 960 |
961 | 962 |
963 | 964 | text-transform 965 | 966 | 986 |
987 | 988 |
989 | 990 |
991 | 992 |
993 | 994 | 995 |
996 | 997 |

998 | Flexbox 999 |

1000 | 1001 |
1002 | 1003 | align-content 1004 | 1005 | 1026 |
1027 | 1028 |
1029 | 1030 | align-items 1031 | 1032 | 1053 |
1054 | 1055 |
1056 | 1057 | align-self 1058 | 1059 | 1080 |
1081 | 1082 |
1083 | 1084 | flex 1085 | 1086 | 1106 |
1107 | 1108 |
1109 | 1110 | flex-direction 1111 | 1112 | 1132 |
1133 | 1134 |
1135 | 1136 | flex-grow 1137 | 1138 | 1156 |
1157 | 1158 |
1159 | 1160 | flex-shrink 1161 | 1162 | 1180 |
1181 | 1182 |
1183 | 1184 | flex-wrap 1185 | 1186 | 1205 |
1206 | 1207 |
1208 | 1209 | flex-justify-content 1210 | 1211 | 1233 |
1234 | 1235 |
1236 | 1237 | order 1238 | 1239 | 1263 |
1264 | 1265 |
1266 | 1267 |
1268 | 1269 |

1270 | Spacing 1271 |

1272 | 1273 |
1274 | 1275 | Overview 1276 | 1277 | 1370 |
1371 | 1372 |
1373 | 1374 | margin 1375 | 1376 | 1429 |
1430 | 1431 |
1432 | 1433 | padding 1434 | 1435 | 1478 |
1479 | 1480 |
1481 | 1482 |
1483 | 1484 |

1485 | Mixins 1486 |

1487 | 1488 |
1489 | 1490 | Make Responsive 1491 | 1492 | 1520 |
1521 | 1522 |
1523 | 1524 | Ratio 1525 | 1526 | 1554 |
1555 | 1556 |
1557 | 1558 |
1559 | 1560 |

1561 | Components 1562 |

1563 | 1564 |
1565 | 1566 | Buttons 1567 | 1568 | 1663 |
1664 | 1665 |
1666 | 1667 | Grids 1668 | 1669 | 1699 |
1700 | 1701 |
1702 | 1703 | List Reset 1704 | 1705 | 1715 |
1716 | 1717 |
1718 | 1719 |
1720 | 1721 |

1722 | Templates 1723 |

1724 | 1725 | 1726 | Index Preview 1727 | 1728 | 1729 | Starter 1730 | 1731 |
1732 | 1733 |

1734 | 1735 | Github 1736 | 1737 |

1738 | 1739 |
1740 | 1741 |
1742 | 1743 |
1744 | 1745 |
1746 | 1747 |
1748 | 1749 | 1750 | 1751 | 1752 | 1753 | 1754 | 1758 | 1802 | 1803 | {% endblock %} 1804 | -------------------------------------------------------------------------------- /src/templates/pages/preview.twig: -------------------------------------------------------------------------------- 1 | {% extends '../layouts/default.twig' %} 2 | {% set head_title = 'Preview Page' %} 3 | {% set body_class = '' %} 4 | 5 | {% block page %} 6 | 7 | 55 | 56 | {% set pages = { 57 | 1: { 58 | t: "Index Page", 59 | u: "index" 60 | }, 61 | 2: { 62 | t: "Starter Page", 63 | u: "starter" 64 | }, 65 | } %} 66 | 67 |
68 |

69 | Project Name 70 |

71 |

72 | This is the demo index page with basic styling. 73 |
74 | It might be used to let a client preview the site. 75 |

76 | 81 |
82 | 83 | {% endblock %} 84 | -------------------------------------------------------------------------------- /src/templates/pages/starter.twig: -------------------------------------------------------------------------------- 1 | {% extends '../layouts/default.twig' %} 2 | {% set head_title = 'Starter Page' %} 3 | {% set body_class = '' %} 4 | {% set menu_active = 'blank-page' %} 5 | 6 | {% block page %} 7 | 8 | {% include '../components/navbar.twig' %} 9 | 10 |
11 | Here goes content. 12 |
13 | 14 | {% include '../components/footer.twig' %} 15 | 16 | {% endblock %} 17 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @title Webpack Config 3 | */ 4 | 5 | // Dependencies 6 | import webpack from 'webpack'; 7 | 8 | // Config 9 | import { paths } from "./gulpfile.babel.js/config"; 10 | 11 | const path = require('path'); 12 | 13 | // Plugins 14 | var WebpackNotifierPlugin = require('webpack-notifier'); 15 | 16 | const webpackConfig = { 17 | 18 | mode: process.env.NODE_ENV ? "production" : "development", 19 | 20 | entry: { 21 | app: paths.scripts.src 22 | }, 23 | output: { 24 | filename: '[name].js', 25 | }, 26 | 27 | module: { 28 | rules: [ 29 | { 30 | test: /^(?!.*\.{test,min}\.js$).*\.js$/, 31 | exclude: /(node_modules)/, 32 | use: { 33 | loader: 'babel-loader', 34 | options: { 35 | presets: ['@babel/preset-env'] 36 | } 37 | } 38 | }, 39 | { 40 | test: /\.s?css$/, 41 | include: /node_modules/, 42 | use: [ 43 | 'style-loader', 44 | 'css-loader', 45 | 'sass-loader', 46 | ], 47 | } 48 | ] 49 | }, 50 | 51 | plugins: [ 52 | // ensure that we get a production build of any dependencies 53 | new webpack.DefinePlugin({ 54 | 'process.env.NODE_ENV': '"production"' 55 | }), 56 | new WebpackNotifierPlugin({ 57 | skipFirstNotification: true 58 | }) 59 | ], 60 | 61 | resolve: { 62 | alias: { 63 | Components: path.resolve(__dirname, 'src/scripts/components/'), 64 | Utils: path.resolve(__dirname, 'src/scripts/utils/') 65 | } 66 | } 67 | 68 | }; 69 | 70 | if (process.env.NODE_ENV === 'production') { 71 | // console.log('Welcome to production'); 72 | webpackConfig.devtool = 'source-map'; 73 | } 74 | if (process.env.NODE_ENV === 'development') { 75 | // console.log('Welcome to development'); 76 | } 77 | 78 | module.exports = webpackConfig; 79 | --------------------------------------------------------------------------------