├── .bowerrc ├── .editorconfig ├── .gitignore ├── .jshintrc ├── .yo-rc.json ├── README.md ├── bower.json ├── e2e ├── main.po.js └── main.spec.js ├── gulp ├── build.js ├── e2e-tests.js ├── inject.js ├── markups.js ├── proxy.js ├── server.js ├── styles.js ├── unit-tests.js └── watch.js ├── gulpfile.js ├── karma.conf.js ├── package.json ├── protractor.conf.js └── src ├── 404.html ├── app ├── index.js ├── main │ ├── main.controller.js │ ├── main.jade │ └── partials │ │ └── mixins.jade └── styles │ ├── index.scss │ └── partials │ ├── _controls.scss │ ├── _diagram.scss │ ├── _global_layout.scss │ ├── _mixins.scss │ ├── _reset.scss │ └── _variables.scss ├── favicon.ico ├── index.html └── tests └── main.controller.spec.js /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "bower_components" 3 | } 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | bower_components/ 3 | .sass-cache/ 4 | .tmp/ 5 | dist/ 6 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "esnext": true, 4 | "bitwise": true, 5 | "camelcase": true, 6 | "curly": true, 7 | "eqeqeq": true, 8 | "immed": true, 9 | "indent": 2, 10 | "latedef": true, 11 | "newcap": true, 12 | "noarg": true, 13 | "quotmark": "single", 14 | "regexp": true, 15 | "undef": true, 16 | "unused": true, 17 | "strict": true, 18 | "trailing": true, 19 | "smarttabs": true, 20 | "white": true, 21 | "validthis": true, 22 | "globals": { 23 | "angular": false, 24 | // Angular Mocks 25 | "inject": false, 26 | // JASMINE 27 | "describe": false, 28 | "it": false, 29 | "before": false, 30 | "beforeEach": false, 31 | "after": false, 32 | "afterEach": false, 33 | "expect": false 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /.yo-rc.json: -------------------------------------------------------------------------------- 1 | { 2 | "generator-gulp-angular": { 3 | "props": { 4 | "paths": { 5 | "src": "src", 6 | "dist": "dist", 7 | "e2e": "e2e", 8 | "tmp": ".tmp" 9 | }, 10 | "angularVersion": "~1.3.4", 11 | "angularModules": [ 12 | { 13 | "name": "angular-animate", 14 | "module": "ngAnimate" 15 | }, 16 | { 17 | "name": "angular-sanitize", 18 | "module": "ngSanitize" 19 | } 20 | ], 21 | "jQuery": { 22 | "name": null, 23 | "version": null 24 | }, 25 | "resource": { 26 | "name": null, 27 | "version": null, 28 | "module": null 29 | }, 30 | "router": { 31 | "name": "angular-ui-router", 32 | "version": "~0.2.13", 33 | "module": "ui.router" 34 | }, 35 | "ui": { 36 | "key": "none", 37 | "name": null, 38 | "version": null, 39 | "module": null 40 | }, 41 | "cssPreprocessor": { 42 | "key": "ruby-sass", 43 | "extension": "scss", 44 | "module": "gulp-ruby-sass", 45 | "version": "~0.7.1" 46 | }, 47 | "jsPreprocessor": { 48 | "key": "none", 49 | "extension": "js", 50 | "srcExtension": "js", 51 | "module": null, 52 | "version": null 53 | }, 54 | "htmlPreprocessor": { 55 | "key": "jade", 56 | "extension": "jade", 57 | "module": "jade", 58 | "version": "~1.8.1" 59 | }, 60 | "bootstrapComponents": { 61 | "name": null, 62 | "version": null, 63 | "key": null, 64 | "module": null 65 | }, 66 | "foundationComponents": { 67 | "name": null, 68 | "version": null, 69 | "key": null, 70 | "module": null 71 | } 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ##Learning Box Model: `box-sizing` 2 | 3 | 4 | 5 | 6 | ###Run/Develop: 7 | 8 | #### Requirements: 9 | - bower, gulp, sass (ruby) 10 | 11 | ``` 12 | npm install -g bower gulp 13 | gem install sass 14 | ``` 15 | 16 | #### Setup 17 | 1. Clone Repo 18 | 2. Install node modules and bower components / dependencies 19 | ``` 20 | npm install && bower install 21 | ``` 22 | 3. Run 23 | ``` 24 | gulp serve 25 | ``` 26 | 27 | 28 | TODO:
29 | - Unit Tests 30 | - ~Add/Remove margin from calculated size~ 31 | - Responsive Styles 32 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cssBoxModel", 3 | "version": "0.0.0", 4 | "dependencies": { 5 | "angular-animate": "~1.3.4", 6 | "angular-sanitize": "~1.3.4", 7 | "angular-ui-router": "~0.2.13", 8 | "angular": "~1.3.4", 9 | "neat": "~1.7.2", 10 | "angular-slider": "~0.2.14" 11 | }, 12 | "devDependencies": { 13 | "angular-mocks": "~1.3.4" 14 | }, 15 | "resolutions": { 16 | "angular": "~1.3.4" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /e2e/main.po.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This file uses the Page Object pattern to define the main page for tests 3 | * https://docs.google.com/presentation/d/1B6manhG0zEXkC-H-tPo2vwU06JhL8w9-XCF9oehXzAQ 4 | */ 5 | 6 | 'use strict'; 7 | 8 | var MainPage = function() { 9 | //TODO 10 | }; 11 | 12 | module.exports = new MainPage(); 13 | -------------------------------------------------------------------------------- /e2e/main.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('The main view', function () { 4 | var page; 5 | 6 | //TODO 7 | 8 | }); 9 | -------------------------------------------------------------------------------- /gulp/build.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | 5 | var paths = gulp.paths; 6 | 7 | var $ = require('gulp-load-plugins')({ 8 | pattern: ['gulp-*', 'main-bower-files', 'uglify-save-license', 'del'] 9 | }); 10 | 11 | gulp.task('partials', ['markups'], function () { 12 | return gulp.src([ 13 | paths.src + '/app/**/*.html', 14 | paths.tmp + '/app/**/*.html' 15 | ]) 16 | .pipe($.minifyHtml({ 17 | empty: true, 18 | spare: true, 19 | quotes: true 20 | })) 21 | .pipe($.angularTemplatecache('templateCacheHtml.js', { 22 | module: 'cssBoxModel' 23 | })) 24 | .pipe(gulp.dest(paths.tmp + '/partials/')); 25 | }); 26 | 27 | gulp.task('html', ['inject', 'partials'], function () { 28 | var partialsInjectFile = gulp.src(paths.tmp + '/partials/templateCacheHtml.js', { read: false }); 29 | var partialsInjectOptions = { 30 | starttag: '', 31 | ignorePath: paths.tmp + '/partials', 32 | addRootSlash: false 33 | }; 34 | 35 | var htmlFilter = $.filter('*.html'); 36 | var jsFilter = $.filter('**/*.js'); 37 | var cssFilter = $.filter('**/*.css'); 38 | var assets; 39 | 40 | return gulp.src(paths.tmp + '/serve/*.html') 41 | .pipe($.inject(partialsInjectFile, partialsInjectOptions)) 42 | .pipe(assets = $.useref.assets()) 43 | .pipe($.rev()) 44 | .pipe(jsFilter) 45 | .pipe($.ngAnnotate()) 46 | .pipe($.uglify({preserveComments: $.uglifySaveLicense})) 47 | .pipe(jsFilter.restore()) 48 | .pipe(cssFilter) 49 | .pipe($.csso()) 50 | .pipe(cssFilter.restore()) 51 | .pipe(assets.restore()) 52 | .pipe($.useref()) 53 | .pipe($.revReplace()) 54 | .pipe(htmlFilter) 55 | .pipe($.minifyHtml({ 56 | empty: true, 57 | spare: true, 58 | quotes: true 59 | })) 60 | .pipe(htmlFilter.restore()) 61 | .pipe(gulp.dest(paths.dist + '/')) 62 | .pipe($.size({ title: paths.dist + '/', showFiles: true })); 63 | }); 64 | 65 | // gulp.task('images', function () { 66 | // return gulp.src(paths.src + '/assets/images/**/*') 67 | // .pipe(gulp.dest(paths.dist + '/assets/images/')); 68 | // }); 69 | 70 | gulp.task('fonts', function () { 71 | return gulp.src($.mainBowerFiles()) 72 | .pipe($.filter('**/*.{eot,svg,ttf,woff}')) 73 | .pipe($.flatten()) 74 | .pipe(gulp.dest(paths.dist + '/fonts/')); 75 | }); 76 | 77 | gulp.task('misc', function () { 78 | return gulp.src(paths.src + '/**/*.ico') 79 | .pipe(gulp.dest(paths.dist + '/')); 80 | }); 81 | 82 | gulp.task('clean', function (done) { 83 | $.del([paths.dist + '/', paths.tmp + '/'], done); 84 | }); 85 | 86 | //removed images b/c have none currently 87 | gulp.task('build', ['html', 'fonts', 'misc']); 88 | -------------------------------------------------------------------------------- /gulp/e2e-tests.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | 5 | var $ = require('gulp-load-plugins')(); 6 | 7 | var browserSync = require('browser-sync'); 8 | 9 | var paths = gulp.paths; 10 | 11 | // Downloads the selenium webdriver 12 | gulp.task('webdriver-update', $.protractor.webdriver_update); 13 | 14 | gulp.task('webdriver-standalone', $.protractor.webdriver_standalone); 15 | 16 | function runProtractor (done) { 17 | 18 | gulp.src(paths.e2e + '/**/*.js') 19 | .pipe($.protractor.protractor({ 20 | configFile: 'protractor.conf.js', 21 | })) 22 | .on('error', function (err) { 23 | // Make sure failed tests cause gulp to exit non-zero 24 | throw err; 25 | }) 26 | .on('end', function () { 27 | // Close browser sync server 28 | browserSync.exit(); 29 | done(); 30 | }); 31 | } 32 | 33 | gulp.task('protractor', ['protractor:src']); 34 | gulp.task('protractor:src', ['serve:e2e', 'webdriver-update'], runProtractor); 35 | gulp.task('protractor:dist', ['serve:e2e-dist', 'webdriver-update'], runProtractor); 36 | -------------------------------------------------------------------------------- /gulp/inject.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | 5 | var paths = gulp.paths; 6 | 7 | var $ = require('gulp-load-plugins')(); 8 | 9 | var wiredep = require('wiredep').stream; 10 | 11 | gulp.task('inject', ['styles'], function () { 12 | 13 | var injectStyles = gulp.src([ 14 | paths.tmp + '/serve/app/**/*.css', 15 | '!' + paths.tmp + '/serve/app/vendor.css' 16 | ], { read: false }); 17 | 18 | var injectScripts = gulp.src([ 19 | paths.src + '/app/**/*.js', 20 | '!' + paths.src + '/app/**/*.spec.js', 21 | '!' + paths.src + '/app/**/*.mock.js' 22 | ]).pipe($.angularFilesort()); 23 | 24 | var injectOptions = { 25 | ignorePath: [paths.src, paths.tmp + '/serve'], 26 | addRootSlash: false 27 | }; 28 | 29 | var wiredepOptions = { 30 | directory: 'bower_components' 31 | }; 32 | 33 | return gulp.src(paths.src + '/*.html') 34 | .pipe($.inject(injectStyles, injectOptions)) 35 | .pipe($.inject(injectScripts, injectOptions)) 36 | .pipe(wiredep(wiredepOptions)) 37 | .pipe(gulp.dest(paths.tmp + '/serve')); 38 | 39 | }); 40 | -------------------------------------------------------------------------------- /gulp/markups.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | 5 | var paths = gulp.paths; 6 | 7 | var $ = require('gulp-load-plugins')(); 8 | 9 | gulp.task('markups', function() { 10 | function renameToHtml(path) { 11 | path.extname = '.html'; 12 | } 13 | 14 | return gulp.src(paths.src + '/{app,components}/**/*.jade') 15 | .pipe($.consolidate('jade', { pretty: ' ' })) 16 | .on('error', function handleError(err) { 17 | console.error(err.toString()); 18 | this.emit('end'); 19 | }) 20 | .pipe($.rename(renameToHtml)) 21 | .pipe(gulp.dest(paths.tmp + '/serve/')); 22 | }); 23 | -------------------------------------------------------------------------------- /gulp/proxy.js: -------------------------------------------------------------------------------- 1 | /*jshint unused:false */ 2 | 3 | /*************** 4 | 5 | This file allow to configure a proxy system plugged into BrowserSync 6 | in order to redirect backend requests while still serving and watching 7 | files from the web project 8 | 9 | IMPORTANT: The proxy is disabled by default. 10 | 11 | If you want to enable it, watch at the configuration options and finally 12 | change the `module.exports` at the end of the file 13 | 14 | ***************/ 15 | 16 | 'use strict'; 17 | 18 | var httpProxy = require('http-proxy'); 19 | var chalk = require('chalk'); 20 | 21 | /* 22 | * Location of your backend server 23 | */ 24 | var proxyTarget = 'http://server/context/'; 25 | 26 | var proxy = httpProxy.createProxyServer({ 27 | target: proxyTarget 28 | }); 29 | 30 | proxy.on('error', function(error, req, res) { 31 | res.writeHead(500, { 32 | 'Content-Type': 'text/plain' 33 | }); 34 | 35 | console.error(chalk.red('[Proxy]'), error); 36 | }); 37 | 38 | /* 39 | * The proxy middleware is an Express middleware added to BrowserSync to 40 | * handle backend request and proxy them to your backend. 41 | */ 42 | function proxyMiddleware(req, res, next) { 43 | /* 44 | * This test is the switch of each request to determine if the request is 45 | * for a static file to be handled by BrowserSync or a backend request to proxy. 46 | * 47 | * The existing test is a standard check on the files extensions but it may fail 48 | * for your needs. If you can, you could also check on a context in the url which 49 | * may be more reliable but can't be generic. 50 | */ 51 | if (/\.(html|css|js|png|jpg|jpeg|gif|ico|xml|rss|txt|eot|svg|ttf|woff|cur)(\?((r|v|rel|rev)=[\-\.\w]*)?)?$/.test(req.url)) { 52 | next(); 53 | } else { 54 | proxy.web(req, res); 55 | } 56 | } 57 | 58 | /* 59 | * This is where you activate or not your proxy. 60 | * 61 | * The first line activate if and the second one ignored it 62 | */ 63 | 64 | //module.exports = [proxyMiddleware]; 65 | module.exports = []; 66 | -------------------------------------------------------------------------------- /gulp/server.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | 5 | var paths = gulp.paths; 6 | 7 | var util = require('util'); 8 | 9 | var browserSync = require('browser-sync'); 10 | 11 | var middleware = require('./proxy'); 12 | 13 | function browserSyncInit(baseDir, files, browser) { 14 | browser = browser === undefined ? 'default' : browser; 15 | 16 | var routes = null; 17 | if(baseDir === paths.src || (util.isArray(baseDir) && baseDir.indexOf(paths.src) !== -1)) { 18 | routes = { 19 | '/bower_components': 'bower_components' 20 | }; 21 | } 22 | 23 | browserSync.instance = browserSync.init(files, { 24 | startPath: '/', 25 | server: { 26 | baseDir: baseDir, 27 | middleware: middleware, 28 | routes: routes 29 | }, 30 | browser: browser 31 | }); 32 | } 33 | 34 | gulp.task('serve', ['watch'], function () { 35 | browserSyncInit([ 36 | paths.tmp + '/serve', 37 | paths.src 38 | ], [ 39 | paths.tmp + '/serve/app/**/*.css', 40 | paths.src + '/app/**/*.js', 41 | // paths.src + 'src/assets/images/**/*', 42 | paths.tmp + '/serve/*.html', 43 | paths.tmp + '/serve/app/**/*.html', 44 | paths.src + '/app/**/*.html' 45 | ]); 46 | }); 47 | 48 | gulp.task('serve:dist', ['build'], function () { 49 | browserSyncInit(paths.dist); 50 | }); 51 | 52 | gulp.task('serve:e2e', ['inject'], function () { 53 | browserSyncInit([paths.tmp + '/serve', paths.src], null, []); 54 | }); 55 | 56 | gulp.task('serve:e2e-dist', ['build'], function () { 57 | browserSyncInit(paths.dist, null, []); 58 | }); 59 | -------------------------------------------------------------------------------- /gulp/styles.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | 5 | var paths = gulp.paths; 6 | 7 | var $ = require('gulp-load-plugins')(); 8 | 9 | gulp.task('styles', function () { 10 | 11 | var sassOptions = { 12 | style: 'expanded' 13 | }; 14 | 15 | var injectFiles = gulp.src([ 16 | paths.src + '/app/styles/**/*.scss', 17 | '!' + paths.src + '/app/styles/index.scss', 18 | '!' + paths.src + '/app/styles/vendor.scss', 19 | '!' + paths.src + '/app/styles/partials/**/*.scss' 20 | ], { read: false }); 21 | 22 | var injectOptions = { 23 | transform: function(filePath) { 24 | filePath = filePath.replace(paths.src + '/app/styles/', ''); 25 | // filePath = filePath.replace(paths.src + '/components/', '../components/'); 26 | return '@import \'' + filePath + '\';'; 27 | }, 28 | starttag: '// injector', 29 | endtag: '// endinjector', 30 | addRootSlash: false 31 | }; 32 | 33 | var indexFilter = $.filter('index.scss'); 34 | 35 | return gulp.src([ 36 | paths.src + '/app/styles/index.scss', 37 | paths.src + '/app/styles/vendor.scss' 38 | ]) 39 | .pipe(indexFilter) 40 | .pipe($.inject(injectFiles, injectOptions)) 41 | .pipe(indexFilter.restore()) 42 | .pipe($.rubySass(sassOptions)) 43 | 44 | .pipe($.autoprefixer()) 45 | .on('error', function handleError(err) { 46 | console.error(err.toString()); 47 | this.emit('end'); 48 | }) 49 | .pipe(gulp.dest(paths.tmp + '/serve/app/')); 50 | }); 51 | -------------------------------------------------------------------------------- /gulp/unit-tests.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | 5 | var $ = require('gulp-load-plugins')(); 6 | 7 | var wiredep = require('wiredep'); 8 | 9 | var paths = gulp.paths; 10 | 11 | function runTests(singleRun, done) { 12 | var bowerDeps = wiredep({ 13 | directory: 'bower_components', 14 | dependencies: true, 15 | devDependencies: true 16 | }); 17 | 18 | var testFiles = bowerDeps.js.concat([ 19 | paths.src + '/{app,components,tests}/**/*.js' 20 | ]); 21 | 22 | gulp.src(testFiles) 23 | .pipe($.karma({ 24 | configFile: 'karma.conf.js', 25 | action: (singleRun) ? 'run' : 'watch' 26 | })) 27 | .on('error', function (err) { 28 | // Make sure failed tests cause gulp to exit non-zero 29 | throw err; 30 | }); 31 | } 32 | 33 | gulp.task('test', function (done) { 34 | runTests(true /* singleRun */ , done) 35 | }); 36 | gulp.task('test:auto', function (done) { 37 | runTests(false /* singleRun */ , done) 38 | }); 39 | -------------------------------------------------------------------------------- /gulp/watch.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | 5 | var paths = gulp.paths; 6 | 7 | gulp.task('watch', ['markups', 'inject'], function () { 8 | gulp.watch([ 9 | paths.src + '/*.html', 10 | paths.src + '/app/styles/**/*.scss', 11 | paths.src + '/app/**/*.js', 12 | 'bower.json' 13 | ], ['inject']); 14 | gulp.watch(paths.src + '/app/main/**/*.jade', ['markups']); 15 | }); 16 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | 5 | gulp.paths = { 6 | src: 'src', 7 | dist: 'dist', 8 | tmp: '.tmp', 9 | e2e: 'e2e' 10 | }; 11 | 12 | require('require-dir')('./gulp'); 13 | 14 | gulp.task('default', ['clean'], function () { 15 | gulp.start('build'); 16 | }); 17 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function (config) { 4 | 5 | config.set({ 6 | color: true, 7 | frameworks: ['jasmine'], 8 | 9 | browsers: ['PhantomJS'], 10 | 11 | plugins: [ 12 | 'karma-phantomjs-launcher', 13 | 'karma-jasmine' 14 | ] 15 | }); 16 | }; 17 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cssBoxModel", 3 | "version": "0.0.0", 4 | "dependencies": {}, 5 | "devDependencies": { 6 | "gulp": "~3.8.10", 7 | "gulp-autoprefixer": "~2.0.0", 8 | "gulp-angular-templatecache": "~1.4.2", 9 | "del": "~0.1.3", 10 | "gulp-consolidate": "~0.1.2", 11 | "gulp-csso": "~0.2.9", 12 | "gulp-filter": "~1.0.2", 13 | "gulp-flatten": "~0.0.4", 14 | "gulp-jshint": "~1.9.0", 15 | "gulp-load-plugins": "~0.7.1", 16 | "gulp-size": "~1.1.0", 17 | "gulp-uglify": "~1.0.1", 18 | "gulp-useref": "~1.0.2", 19 | "gulp-ng-annotate": "^0.5.0", 20 | "gulp-replace": "~0.5.0", 21 | "gulp-rename": "~1.2.0", 22 | "gulp-rev": "~2.0.1", 23 | "gulp-rev-replace": "~0.3.1", 24 | "gulp-minify-html": "~0.1.7", 25 | "gulp-inject": "~1.0.2", 26 | "gulp-protractor": "~0.0.11", 27 | "gulp-karma": "~0.0.4", 28 | "gulp-ruby-sass": "~0.7.1", 29 | "gulp-angular-filesort": "~1.0.4", 30 | "jade": "~1.8.1", 31 | "main-bower-files": "~2.4.0", 32 | "jshint-stylish": "~1.0.0", 33 | "wiredep": "~2.2.0", 34 | "karma-jasmine": "~0.3.1", 35 | "karma-phantomjs-launcher": "~0.1.4", 36 | "require-dir": "~0.1.0", 37 | "browser-sync": "~1.7.1", 38 | "http-proxy": "~1.7.0", 39 | "chalk": "~0.5.1", 40 | "protractor": "~1.4.0", 41 | "uglify-save-license": "~0.4.1" 42 | }, 43 | "engines": { 44 | "node": ">=0.10.0" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /protractor.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var paths = require('./.yo-rc.json')['generator-gulp-angular'].props.paths; 4 | 5 | // An example configuration file. 6 | exports.config = { 7 | // The address of a running selenium server. 8 | //seleniumAddress: 'http://localhost:4444/wd/hub', 9 | //seleniumServerJar: deprecated, this should be set on node_modules/protractor/config.json 10 | 11 | // Capabilities to be passed to the webdriver instance. 12 | capabilities: { 13 | 'browserName': 'chrome' 14 | }, 15 | 16 | // Spec patterns are relative to the current working directly when 17 | // protractor is called. 18 | specs: [paths.e2e + '/**/*.js'], 19 | 20 | // Options to be passed to Jasmine-node. 21 | jasmineNodeOpts: { 22 | showColors: true, 23 | defaultTimeoutInterval: 30000 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /src/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Page Not Found :( 6 | 141 | 142 | 143 |
144 |

Not found :(

145 |

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

146 |

It looks like this was the result of either:

147 | 151 | 154 | 155 |
156 | 157 | 158 | -------------------------------------------------------------------------------- /src/app/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('cssBoxModel', ['ngAnimate', 'ngSanitize', 'ui.router','ui.slider']) 4 | 5 | .config(function($stateProvider, $urlRouterProvider) { 6 | $stateProvider 7 | .state('home', { 8 | url: '/', 9 | templateUrl: 'app/main/main.html', 10 | controller: 'MainCtrl' 11 | }); 12 | 13 | $urlRouterProvider.otherwise('/'); 14 | }) 15 | 16 | .directive('labelPositionV', function() { 17 | return { 18 | restrict: 'AE', 19 | scope: {}, 20 | link: function(scope, element, attrs, ctrl) { 21 | var id = attrs.id; 22 | attrs.$observe('labelPositionTop', function(value) { 23 | var styleTop = ""; 24 | angular.element(document).find('head').append(styleTop); 25 | }); 26 | attrs.$observe('labelPositionBottom', function(value) { 27 | var styleBottom = ""; 28 | angular.element(document).find('head').append(styleBottom); 29 | }); 30 | } 31 | }; 32 | }) 33 | 34 | .directive('labelPositionH', function() { 35 | return { 36 | restrict: 'AE', 37 | scope: {}, 38 | link: function(scope, element, attrs, ctrl) { 39 | var id = attrs.id; 40 | attrs.$observe('labelPositionRight', function(value) { 41 | var styleRight = ""; 42 | angular.element(document).find('head').append(styleRight); 43 | }); 44 | attrs.$observe('labelPositionLeft', function(value) { 45 | var styleLeft = ""; 46 | angular.element(document).find('head').append(styleLeft); 47 | }); 48 | 49 | } 50 | }; 51 | }); 52 | -------------------------------------------------------------------------------- /src/app/main/main.controller.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var app = angular.module('cssBoxModel'); 3 | 4 | app.controller('MainCtrl', function ($scope) { 5 | 6 | //models: default adjustable values 7 | $scope.padding = { 8 | top: 20, 9 | right: 20, 10 | bottom: 20, 11 | left: 20, 12 | v: function () { 13 | return this.top + this.bottom; 14 | }, 15 | h: function () { 16 | return this.right + this.left; 17 | } 18 | }; 19 | 20 | $scope.border = { 21 | top: 15, 22 | right: 15, 23 | bottom: 15, 24 | left: 15, 25 | v: function () { 26 | return this.top + this.bottom; 27 | }, 28 | h: function () { 29 | return this.right + this.left; 30 | } 31 | }; 32 | 33 | $scope.margin = { 34 | top: 20, 35 | right: 20, 36 | bottom: 20, 37 | left: 20, 38 | v: function () { 39 | return this.top + this.bottom; 40 | }, 41 | h: function () { 42 | return this.right + this.left; 43 | } 44 | }; 45 | 46 | $scope.box = { 47 | sizing: 'content-box' 48 | }; 49 | 50 | $scope.dimensions = { 51 | width: 220, 52 | height: 220 53 | }; 54 | 55 | $scope.innerContent = { 56 | width: getInnerWidth(), 57 | height: getInnerHeight() 58 | }; 59 | 60 | $scope.generatedIncludeMargin = false; 61 | 62 | $scope.generatedBoxDimensions = { 63 | width: getGeneratedBoxDimensionsWidth(), 64 | height: getGeneratedBoxDimensionsHeight() 65 | }; 66 | 67 | $scope.checkIncludeMargin = function() { 68 | $scope.generatedBoxDimensions.width = getGeneratedBoxDimensionsWidth(); 69 | $scope.generatedBoxDimensions.height = getGeneratedBoxDimensionsHeight(); 70 | }; 71 | 72 | 73 | //actual applied style values 74 | $scope.boxPosition = { 75 | left: 50, 76 | top: 56 77 | }; 78 | 79 | $scope.styleMargin = { 80 | width: 300, 81 | height: 300, 82 | top: -50, 83 | left: -50 84 | }; 85 | 86 | $scope.styleBorder = { 87 | width: 260, 88 | height: 260, 89 | top: -30, 90 | left: -30 91 | }; 92 | 93 | $scope.stylePadding = { 94 | width: 242, 95 | height: 242, 96 | top: -20, 97 | left: -20 98 | }; 99 | 100 | //watch for changes applied to sliders and calculate rendered styles 101 | $scope.$watch(function () { 102 | $scope.boxPosition.top = calcBoxPositionTop() + 6; 103 | $scope.boxPosition.left = calcBoxPositionLeft(); 104 | 105 | //Margin Styles 106 | $scope.styleMargin.width = $scope.margin.h() + $scope.styleBorder.width; 107 | $scope.styleMargin.height = $scope.margin.v() + $scope.styleBorder.height; 108 | $scope.styleMargin.top = -calcBoxPositionTop(); 109 | $scope.styleMargin.left = -calcBoxPositionLeft(); 110 | 111 | //Border Styles 112 | $scope.styleBorder.width = $scope.border.h() + $scope.stylePadding.width; 113 | $scope.styleBorder.height = $scope.border.v() + $scope.stylePadding.height; 114 | $scope.styleBorder.top = -($scope.border.top + $scope.padding.top); 115 | $scope.styleBorder.left = -($scope.border.left + $scope.padding.left); 116 | 117 | //Padding Styles 118 | $scope.stylePadding.width = $scope.padding.h() + getInnerWidth() + 2; 119 | $scope.stylePadding.height = $scope.padding.v() + getInnerHeight() + 2; 120 | $scope.stylePadding.top = -$scope.padding.top; 121 | $scope.stylePadding.left = -$scope.padding.left; 122 | 123 | //Inner Content Styles- based on box-sizing 124 | $scope.innerContent.width = getInnerWidth(); 125 | $scope.innerContent.height = getInnerHeight(); 126 | 127 | //Generated Dimensions- based on box-sizing 128 | $scope.generatedBoxDimensions.width = getGeneratedBoxDimensionsWidth(); 129 | $scope.generatedBoxDimensions.height = getGeneratedBoxDimensionsHeight(); 130 | }); 131 | 132 | function getInnerWidth() { 133 | var width; 134 | if ($scope.box.sizing === 'border-box') { 135 | width = $scope.dimensions.width - 136 | $scope.border.h() - 137 | $scope.padding.h(); 138 | } else { 139 | width = $scope.dimensions.width; 140 | } 141 | return (width > 0) ? width : 0; 142 | } 143 | 144 | function getInnerHeight() { 145 | var height; 146 | if ($scope.box.sizing === 'border-box') { 147 | height = $scope.dimensions.height - 148 | $scope.border.v() - 149 | $scope.padding.v(); 150 | } else { 151 | height = $scope.dimensions.height; 152 | } 153 | return (height > 0) ? height : 0; 154 | } 155 | 156 | 157 | //if padding + border > dimension, return (padding + border - dimension) [+ margin] 158 | function getGeneratedBoxDimensionsWidth() { 159 | var width; 160 | if ($scope.box.sizing === 'border-box') { 161 | width = (getInnerWidth() === 0) ? calcPaddingBorderWidth() : $scope.dimensions.width; 162 | } else { 163 | width = $scope.dimensions.width + calcPaddingBorderWidth(); 164 | } 165 | return ($scope.generatedIncludeMargin) ? width + $scope.margin.h() : width; 166 | } 167 | 168 | function getGeneratedBoxDimensionsHeight() { 169 | var height; 170 | if ($scope.box.sizing === 'border-box') { 171 | height = (getInnerHeight() === 0) ? calcPaddingBorderHeight() : $scope.dimensions.height; 172 | } else { 173 | height = $scope.dimensions.height + calcPaddingBorderHeight(); 174 | } 175 | return ($scope.generatedIncludeMargin) ? height + $scope.margin.v() : height; 176 | } 177 | 178 | /* 179 | * Private: Helpers 180 | */ 181 | function calcBoxPositionTop() { 182 | return $scope.margin.top + $scope.border.top + $scope.padding.top; 183 | } 184 | 185 | function calcBoxPositionLeft() { 186 | return $scope.margin.left + $scope.border.left + $scope.padding.left; 187 | } 188 | 189 | function calcPaddingBorderWidth() { 190 | return $scope.padding.h() + $scope.border.h(); 191 | } 192 | 193 | function calcPaddingBorderHeight() { 194 | return $scope.padding.v() + $scope.border.v(); 195 | } 196 | 197 | }); 198 | -------------------------------------------------------------------------------- /src/app/main/main.jade: -------------------------------------------------------------------------------- 1 | include partials/mixins 2 | 3 | main 4 | section.controls 5 | div.control-set#box-sizing 6 | fieldset 7 | legend#bs box-sizing 8 | label 9 | input(type="radio", ng-model="box.sizing", value="content-box" class="radio") 10 | | content-box 11 | label 12 | input(type="radio", ng-model="box.sizing", value="border-box" class="radio") 13 | | border-box 14 | 15 | //- extract to mixin? 16 | //- meh, maybe no 17 | each attr in ["padding","border","margin"] 18 | div.control-set(id=attr) 19 | fieldset 20 | legend= attr 21 | .sliders 22 | each val in ["top", "right", "bottom", "left"] 23 | label #{attr}-#{val} 24 | slider(floor="0" ceiling="120" step="5" precision="1" ng-model="#{attr}.#{val}" highlight="left") 25 | div.value {{#{attr}.#{val}}}px 26 | 27 | section.box-model 28 | div.control-set#content 29 | fieldset 30 | legend Dimensions 31 | .sliders 32 | label width 33 | slider(floor="0" ceiling="400" step="10" precision="1" ng-model="dimensions.width" highlight="left") 34 | div.value {{dimensions.width}}px 35 | label height 36 | slider(floor="0" ceiling="400" step="10" precision="1" ng-model="dimensions.height" highlight="left") 37 | div.value {{dimensions.height}}px 38 | div.control-set#generated-size 39 | fieldset 40 | legend Generated Size 41 | input#toggle-include-margin.toggle(type="checkbox", checked="", ng-model="generatedIncludeMargin", ng-change="checkIncludeMargin()") 42 | label.toggle-control(for="toggle-include-margin") 43 | span.toggle-text include margin 44 | div.generated-width horizontal: {{generatedBoxDimensions.width}}px 45 | div.generated-height vertical: {{generatedBoxDimensions.height}}px 46 | div#diagram 47 | .box(ng-style="{'top': boxPosition.top+'px', 'left': boxPosition.left+'px', 'width': dimensions.width+'px', 'height': dimensions.height+'px'}") 48 | .box-margin.box-property(ng-style="{'width': styleMargin.width+'px', 'height': styleMargin.height+'px', 'top': styleMargin.top+'px', 'left': styleMargin.left+'px'}") 49 | span.property-label#property-label-margin margin 50 | span#margin-v.box-property-vertical(data-id="margin-v", data-top="{{margin.top}}", data-bottom="{{margin.bottom}}", label-position-top="{{margin.top}}", label-position-bottom="{{margin.bottom}}", label-position-v="") 51 | span#margin-h.box-property-horizontal(data-id="margin-h", data-left="{{margin.left}}", data-right="{{margin.right}}", label-position-right="{{margin.right}}", label-position-left="{{margin.left}}", label-position-h="") 52 | .box-border.box-property(ng-style="{'width': styleBorder.width+'px', 'height': styleBorder.height+'px', 'top': styleBorder.top+'px', 'left': styleBorder.left+'px'}") 53 | span.property-label#property-label-border border 54 | span#border-v.box-property-vertical(data-id="border-v", data-top="{{border.top}}", data-bottom="{{border.bottom}}", label-position-top="{{border.top}}", label-position-bottom="{{border.bottom}}", label-position-v="") 55 | span#border-h.box-property-horizontal(data-id="border-h", data-left="{{border.left}}", data-right="{{border.right}}", label-position-right="{{border.right}}", label-position-left="{{border.left}}", label-position-h="") 56 | .box-padding.box-property(ng-style="{'width': stylePadding.width+'px', 'height': stylePadding.height+'px', 'top': stylePadding.top+'px', 'left': stylePadding.left+'px'}") 57 | span.property-label#property-label-padding padding 58 | span#padding-v.box-property-vertical(data-id="padding-v", data-top="{{padding.top}}", data-bottom="{{padding.bottom}}", label-position-top="{{padding.top}}", label-position-bottom="{{padding.bottom}}", label-position-v="") 59 | span#padding-h.box-property-horizontal(data-id="padding-h", data-left="{{padding.left}}", data-right="{{padding.right}}", label-position-right="{{padding.right}}", label-position-left="{{padding.left}}", label-position-h="") 60 | .box-inner.box-property(ng-style="{'width': innerContent.width+'px', 'height': innerContent.height+'px'}", data-height="{{innerContent.height}}", data-width="{{innerContent.width}}") 61 | span.property-label#property-label-content content 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /src/app/main/partials/mixins.jade: -------------------------------------------------------------------------------- 1 | mixin controlset 2 | each attr in ["margin", "padding", "border"] 3 | div.control-set 4 | each val in ["top", "right", "bottom", "left"] 5 | label #{attr}-#{val} 6 | slider(ng-model="#{attr}.#{val}") 7 | div.value {{#{attr}.#{val}}}px 8 | -------------------------------------------------------------------------------- /src/app/styles/index.scss: -------------------------------------------------------------------------------- 1 | @import "../../../bower_components/bourbon/app/assets/stylesheets/bourbon"; 2 | @import "../../../bower_components/neat/app/assets/stylesheets/neat"; 3 | 4 | @import "partials/reset"; 5 | @import "partials/variables"; 6 | @import "partials/mixins"; 7 | 8 | @import "partials/global_layout"; 9 | @import "partials/controls"; 10 | @import "partials/diagram"; 11 | 12 | // injector 13 | // endinjector 14 | -------------------------------------------------------------------------------- /src/app/styles/partials/_controls.scss: -------------------------------------------------------------------------------- 1 | $color-margin: #DE6A63; 2 | $color-padding: #C5D936; 3 | $color-content: #63BCF8; 4 | $color-border: #F8CC63; 5 | $color-box-sizing: #8ADFE0; 6 | 7 | $color-bg: #242930; 8 | $color-dark-light: #343434; 9 | $color-dark-lighter: #444; 10 | $color-dark-lightest: #777; 11 | $color-body: #808386; 12 | $color-white: #FFFFFF; 13 | 14 | 15 | $knob-size: 20px; 16 | $knob-border-width: 3px; 17 | 18 | $boxes: (content: $color-content, 19 | padding: $color-padding, 20 | border: $color-border, 21 | margin: $color-margin, 22 | box-sizing: $color-box-sizing, 23 | generated-size: $color-content); 24 | 25 | $sliders: content, padding, border, margin; 26 | 27 | 28 | $lg: new-breakpoint(min-width 1245px 7); 29 | $md: new-breakpoint(min-width 950px); 30 | $sm: new-breakpoint(min-width 790px 6); 31 | 32 | 33 | /***************************************** 34 | * CONTROL STYLES 35 | ******************************************/ 36 | 37 | // Fieldset/Legend 38 | // --------------------------------------- 39 | 40 | fieldset { 41 | border: 1px solid $color-dark-light; 42 | padding: 0 10px 5px; 43 | } 44 | 45 | #generated-size fieldset { 46 | min-height: 114px; 47 | } 48 | 49 | legend { 50 | text-transform: uppercase; 51 | font-weight: 300; 52 | font-size: 1.3em; 53 | } 54 | 55 | @each $property, $color in $boxes { 56 | ##{$property} { 57 | legend { 58 | color: $color; 59 | } 60 | } 61 | } 62 | 63 | label, .value, .toggle-text { 64 | font-size: 60%; 65 | display: inline-block; 66 | white-space: nowrap; 67 | font-family: unquote(map-get($bodytype, font-family)); 68 | letter-spacing: 1.5px; 69 | } 70 | 71 | .control-set { 72 | margin-top: 20px; 73 | width: 100%; 74 | label, .toggle-text { 75 | width: 25%; 76 | text-transform: uppercase; 77 | } 78 | .slider { 79 | width: 65%; 80 | @include media($md) { 81 | width: 55%; 82 | } 83 | @include media($lg) { 84 | width: 63%; 85 | } 86 | } 87 | .value { 88 | width: 7%; 89 | text-align: right; 90 | } 91 | } 92 | 93 | .box-model #content label { 94 | width: 25%; 95 | @include media($md) { 96 | width: 22%; 97 | } 98 | } 99 | 100 | #box-sizing label { 101 | width: 40%; 102 | } 103 | 104 | 105 | 106 | // Radio Button 107 | // --------------------------------------- 108 | .radio { 109 | position: relative; 110 | margin: 0 1rem 0 0; 111 | cursor: pointer; 112 | &::before, 113 | &::after { 114 | @include transition(all 0.3s ease-in-out); 115 | content: ""; 116 | position: absolute; 117 | top: -0.2rem; 118 | left: -0.2rem; 119 | z-index: 1; 120 | width: $knob-size; 121 | height: $knob-size; 122 | background: $color-dark-light !important; 123 | border-radius: 50%; 124 | } 125 | &:checked, 126 | &.ng-valid-parse { 127 | &::before { 128 | @include transform(scale(0, 0)); 129 | border-color: $color-box-sizing !important; 130 | border-width: $knob-border-width !important; 131 | } 132 | &::after { 133 | border: $knob-border-width solid $color-box-sizing !important; 134 | background: $color-bg !important; 135 | } 136 | } 137 | } 138 | 139 | // Range Sliders 140 | // --------------------------------------- 141 | slider, [slider] { 142 | display: inline-block; 143 | position: relative; 144 | height: 7px; 145 | width: 63%; 146 | vertical-align: middle; 147 | margin: 5px; 148 | div { 149 | white-space: nowrap; 150 | position: absolute; 151 | &.handle { 152 | border: $knob-border-width solid; 153 | cursor: pointer; 154 | width: $knob-size; 155 | height: $knob-size; 156 | top: -8px; 157 | background-color: $color-bg; 158 | z-index: 2; 159 | border-radius: 100%; 160 | &::after { 161 | content: ''; 162 | width: 8px; 163 | height: 8px; 164 | position: absolute; 165 | left: 6px; 166 | border-radius: 100%; 167 | background-color: transparent; 168 | } 169 | &.active::after { 170 | background-color: transparent; 171 | } 172 | } 173 | &.bar { 174 | width: 100%; 175 | height: 100%; 176 | border-radius: 7px; 177 | background: $color-dark-lighter; 178 | overflow: hidden; 179 | .selection { 180 | width: 0; 181 | height: 100%; 182 | } 183 | } 184 | // TODO: remove Bubble functionality from slider directive 185 | &.bubble { 186 | display: none; 187 | cursor: default; 188 | top: -22px; 189 | padding: 1px 3px; 190 | font-size: 0.7em; 191 | &.active { 192 | display: inline-block; 193 | } 194 | &.limit { 195 | color: $color-dark-lightest; 196 | } 197 | } 198 | } 199 | } 200 | 201 | .bubble.value.low.ng-binding.active { 202 | display: none; 203 | } 204 | 205 | .bar-color { 206 | height: 20px; 207 | border-right: 3px solid; 208 | box-sizing: content-box; 209 | } 210 | 211 | @each $property in $sliders { 212 | ##{$property} { 213 | .slider-selection, .bar-color { 214 | background-color: unquote(map-get($boxes, #{$property})); 215 | } 216 | .bar-color, 217 | .handle { 218 | border-color: unquote(map-get($boxes, #{$property})); 219 | } 220 | } 221 | } 222 | 223 | @media (min-width: 951px) and (max-width: 1244px) { 224 | .controls { 225 | .sliders label { 226 | display: block; 227 | line-height: 1rem; 228 | &:first-of-type { 229 | margin-top: 8px; 230 | } 231 | } 232 | slider, [slider] { 233 | width: 87%; 234 | } 235 | } 236 | } 237 | 238 | // Toggle 239 | // --------------------------------------- 240 | .toggle { 241 | display: none; 242 | &, &::after, &::before, & *, & *::after, & *::before, & + .toggle-control { 243 | box-sizing: border-box; 244 | &::selection { 245 | background: none; 246 | } 247 | } 248 | + .toggle-control { 249 | outline: 0; 250 | top: 10px; 251 | margin-bottom: 8px; 252 | width: 52px; 253 | position: relative; 254 | cursor: pointer; 255 | user-select: none; 256 | padding: 3px; 257 | @include transition(all 0.3s ease-in-out); 258 | background: $color-bg; 259 | border: $knob-border-width/2 solid $color-dark-lighter; 260 | border-radius: 2em; 261 | &::after, &::before { 262 | position: relative; 263 | display: block; 264 | content:""; 265 | width: $knob-size; 266 | height: $knob-size; 267 | } 268 | &::after { 269 | left: 0; 270 | @include transition(all 0.3s ease-in-out); 271 | background: $color-dark-light; 272 | border-radius: 50%; 273 | } 274 | &::before { 275 | display: none; 276 | } 277 | } 278 | &:checked { 279 | + .toggle-control { 280 | border: $knob-border-width/2 solid $color-dark-lighter; 281 | &::after { 282 | left: 50%; 283 | height: $knob-size; 284 | width: $knob-size; 285 | background: $color-bg; 286 | border: $knob-border-width solid $color-content; 287 | } 288 | } 289 | } 290 | } 291 | .toggle-text { 292 | vertical-align: text-bottom; 293 | margin-left: 5px; 294 | } 295 | 296 | 297 | // Generated Size Change Animation (ng-animate) 298 | // --------------------------------------- 299 | .generated-direction { 300 | display: inline-block; 301 | width: 150px; 302 | } 303 | 304 | .generated-width, 305 | .generated-height { 306 | font-size: 60%; 307 | white-space: nowrap; 308 | font-family: unquote(map-get($bodytype, font-family)); 309 | letter-spacing: 1.5px; 310 | text-transform: uppercase; 311 | line-height: 3rem; 312 | @include media($sm) { 313 | line-height: 2rem; 314 | } 315 | .changes { 316 | text-transform: none; 317 | display: inline-block; 318 | line-height: 25px; 319 | padding: 0 5px; 320 | background: #2F353E; 321 | border-radius: 3px; 322 | color: $color-content; 323 | @include transition(color 0.4s ease-in-out, background 0.4s ease-in-out); 324 | &[class*="-add"] { 325 | color: darken($color-content, 45%); 326 | background: $color-content; 327 | } 328 | &.highlight { 329 | &.ng-enter { 330 | background: #2F353E; 331 | color: $color-content; 332 | &.ng-enter-active { 333 | color: darken($color-content, 45%); 334 | background: $color-content; 335 | } 336 | } 337 | &.ng-leave { 338 | color: darken($color-content, 45%); 339 | background: $color-content; 340 | &.ng-leave-active { 341 | background: #2F353E; 342 | color: $color-content; 343 | } 344 | } 345 | } 346 | } 347 | } 348 | -------------------------------------------------------------------------------- /src/app/styles/partials/_diagram.scss: -------------------------------------------------------------------------------- 1 | $color-margin: #DE6A63; 2 | $color-padding: #C5D936; 3 | $color-content: #63BCF8; 4 | $color-border: #F8CC63; 5 | $color-box-sizing: #8ADFE0; 6 | 7 | $color-bg: #242930; 8 | $color-dark-light: #343434; 9 | $color-dark-lighter: #444; 10 | $color-dark-lightest: #777; 11 | $color-body: #808386; 12 | $color-white: #FFFFFF; 13 | 14 | 15 | $knob-size: 20px; 16 | $knob-border-width: 3px; 17 | 18 | $boxes: (content: $color-content, 19 | padding: $color-padding, 20 | border: $color-border, 21 | margin: $color-margin, 22 | box-sizing: $color-box-sizing, 23 | generated-size: $color-content); 24 | 25 | $sliders: content, padding, border, margin; 26 | 27 | $lg: new-breakpoint(min-width 1245px 7); 28 | $md: new-breakpoint(min-width 950px); 29 | $sm: new-breakpoint(min-width 790px 6); 30 | /***************************************** 31 | * DIAGRAM STYLES 32 | ******************************************/ 33 | 34 | #diagram { 35 | margin-left: 5px; 36 | clear: left; 37 | padding-top: $gutter; 38 | } 39 | 40 | .box { 41 | position: relative; 42 | &:hover { 43 | .box-property { 44 | background: $color-white; 45 | } 46 | .box-property-vertical, 47 | .box-property-horizontal { 48 | opacity: 0; 49 | } 50 | } 51 | } 52 | 53 | .box-property { 54 | font-family: unquote(map-get($monospacetype, font-family)); 55 | @include transition(width 0.3s linear, height 0.3s linear); 56 | position: absolute; 57 | } 58 | 59 | .box-padding { 60 | @include box-styles($color-padding, dashed, true, 40%); 61 | } 62 | .box-border { 63 | @include box-styles($color-border, solid, true, 50%); 64 | } 65 | .box-margin { 66 | @include box-styles($color-margin, dashed, true, 60%); 67 | /** To Decode this SVG image, paste the css here: www.svgeneration.com/tools/base-64-decoder */ 68 | 69 | background-color: #de6a63; 70 | background-image:url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPSc3JyBoZWlnaHQ9JzE0JyB2aWV3Qm94PScwIDAgNSAxMCc+Cgk8cmVjdCB3aWR0aD0nMTEwJScgeD0nLTUlJyB5PSctNSUnIGhlaWdodD0nMTEwJScgZmlsbD0nI2RlNmE2MycvPgoJPGxpbmUgeDE9JzcnIHkxPScxJyB4Mj0nLTInIHkyPScxMCcgc3Ryb2tlPScjZWVhYWE1JyBzdHJva2Utd2lkdGg9JzAuMjknLz4KCTxsaW5lIHgxPSc3JyB5MT0nNicgeDI9Jy0yJyB5Mj0nMTUnIHN0cm9rZT0nI2VlYWFhNScgc3Ryb2tlLXdpZHRoPScwLjI5Jy8+Cgk8bGluZSB4MT0nNycgeTE9Jy00JyB4Mj0nLTInIHkyPSc1JyBzdHJva2U9JyNlZWFhYTUnIHN0cm9rZS13aWR0aD0nMC4yOScvPgo8L3N2Zz4='); 71 | 72 | } 73 | 74 | .box-inner { 75 | @include box-styles($color-content, solid); 76 | text-align: center; 77 | &::before { 78 | color: darken($color-content, 35%); 79 | content: attr(data-width) " x " attr(data-height); 80 | position: absolute; 81 | left: 0; 82 | top: 50%; 83 | margin-top: .5em; 84 | width: 100%; 85 | font-size: .75em; 86 | white-space: nowrap; 87 | } 88 | } 89 | 90 | 91 | 92 | // Box-Property Main Labels 93 | // --------------------------------------- 94 | .property-label { 95 | font-family: unquote(map-get($headingtype, font-family)); 96 | text-transform: uppercase; 97 | font-weight: 400; 98 | letter-spacing: 2px; 99 | font-size: 11px; 100 | top: -6px; 101 | @include media($sm) { 102 | top: -12px; 103 | } 104 | 105 | left: 5px; 106 | position: relative; 107 | &#property-label-padding { 108 | color: darken($color-padding, 15%); 109 | } 110 | &#property-label-border { 111 | color: darken($color-border, 28%); 112 | } 113 | &#property-label-margin { 114 | color: darken($color-margin, 20%); 115 | } 116 | &#property-label-content { 117 | color: darken($color-content, 20%); 118 | float: left; 119 | top: -6px; 120 | @include media($sm) { 121 | top: -8px; 122 | } 123 | } 124 | } 125 | 126 | #padding-v::before { 127 | top: -8px; 128 | } 129 | 130 | %box-property-position { 131 | position: absolute; 132 | top: 0; 133 | left: 0; 134 | z-index: 2000; 135 | &::before, &::after { 136 | position: absolute; 137 | font-size: 0.75em; 138 | text-align: center; 139 | } 140 | } 141 | 142 | %property-vertical { 143 | left: -0.5em; 144 | width: 100%; 145 | } 146 | 147 | %property-horizontal { 148 | margin-top: -0.65em; 149 | width: 2em; 150 | height: 100%; 151 | } 152 | 153 | $properties: zip(vertical horizontal, height width, top left, bottom right, -0.5em -1em); 154 | 155 | @each $direction, $dimension, $offset-before, $offset-after, $amount in $properties { 156 | .box-property-#{$direction} { 157 | @extend %box-property-position; 158 | #{$dimension}: 100%; 159 | &::before { 160 | content:attr(data-#{$offset-before}); 161 | @extend %property-#{$direction}; 162 | #{$offset-before}: $amount; 163 | } 164 | &::after { 165 | content: attr(data-#{$offset-after}); 166 | @extend %property-#{$direction}; 167 | #{$offset-after}: $amount; 168 | } 169 | } 170 | } 171 | 172 | -------------------------------------------------------------------------------- /src/app/styles/partials/_global_layout.scss: -------------------------------------------------------------------------------- 1 | 2 | .browsehappy { 3 | margin: 0.2em 0; 4 | background: #CCC; 5 | color: #000; 6 | padding: 0.2em 0; 7 | } 8 | 9 | // Site-wide base styles. 10 | // Setting root sizes and base styles. 11 | html { 12 | -webkit-text-size-adjust: 100%; 13 | -ms-text-size-adjust: 100%; 14 | @include rootsize; 15 | } 16 | 17 | body { 18 | background-color: $color-bg; 19 | color: $color-body; 20 | overflow-x: hidden; 21 | font-family: unquote(map-get($bodytype, font-family)); 22 | font-style: normal; 23 | font-weight: map-get($bodytype, regular); 24 | line-height: 2rem; 25 | @include fontsize(zeta, all); 26 | } 27 | 28 | main { 29 | margin: 20px auto; 30 | padding: 0 20px; 31 | @include outer-container; 32 | } 33 | 34 | $lg: new-breakpoint(min-width 1245px 7); 35 | $md: new-breakpoint(min-width 950px); 36 | $sm: new-breakpoint(min-width 790 6); 37 | // $shorter-sliders: new-breakpoint(min-width 950px); 38 | // $block-labels: new-breakpoint(max-width 950px); 39 | // $md-sm: new-breakpoint(max-width 790px 6); 40 | 41 | .box-model { 42 | @include media($sm) { 43 | @include span-columns(6); 44 | } 45 | @include media($md) { 46 | @include span-columns(7); 47 | } 48 | #content, #generated-size { 49 | @include media($lg) { 50 | @include span-columns(4 of 7); 51 | } 52 | } 53 | #generated-size { 54 | @include media($lg) { 55 | @include span-columns(3 of 7); 56 | @include omega; 57 | } 58 | } 59 | } 60 | 61 | .controls { 62 | @include media($sm) { 63 | @include span-columns(6); 64 | } 65 | @include media($md) { 66 | @include span-columns(5); 67 | } 68 | } 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /src/app/styles/partials/_mixins.scss: -------------------------------------------------------------------------------- 1 | // BOX Style mixins 2 | // -------------------------------------- 3 | 4 | @mixin box-property-labels($position) { 5 | .box-property-vertical { 6 | left: $position; 7 | } 8 | .box-property-horizontal { 9 | top: $position; 10 | } 11 | } 12 | 13 | @mixin stagger-labels($position) { 14 | .box-property-vertical { 15 | left: $position; 16 | } 17 | .box-property-horizontal { 18 | top: $position; 19 | } 20 | } 21 | 22 | %hover-opacity { 23 | opacity: 1; 24 | } 25 | 26 | @mixin box-styles($color, $border-style, $position-outer:false, $position:0) { 27 | background: $color; 28 | border: 1px $border-style lighten($color-body, 45%); 29 | text-shadow: 0px 1px 1px transparentize(lighten($color, 20%), 0.3); 30 | span::before, 31 | span::after { 32 | color: darken($color, 40%); 33 | } 34 | &:hover { 35 | background-color: $color !important; 36 | @if position-outer { 37 | .box-property-vertical, 38 | .box-property-horizontal { 39 | @extend %hover-opacity; 40 | opacity: 1; 41 | } 42 | } 43 | } 44 | @if $position-outer { 45 | @include stagger-labels($position); 46 | } 47 | } 48 | 49 | 50 | 51 | 52 | // SCSS mixins 53 | // --------------------------------------- 54 | 55 | // Global variables used in mixins. 56 | 57 | // Number of breakpoints. 58 | $breakpoints-limit: length($breakpoints); 59 | 60 | // List of rootsizes, breakpoints, and max-widths. 61 | $sizes: map-values($rootsizes); 62 | $points: map-values($breakpoints); 63 | $line-widths: map-values($measures); 64 | $max-widths: map-values($maxwidths); 65 | 66 | 67 | // Breakpoints. Either set one to one of the breakpoint variables, or use a custom value for minor breakpoints. 68 | // Defaults to min-width, but both min->max and max-width are available too. 69 | // Parts based on https://gist.github.com/timknight/03e6335b8816aa534cf7 70 | @mixin breakpoint($break: 0, $max: 0) { 71 | // Type of break variable 72 | $value: type-of($break); 73 | 74 | // If it is a string (i.e. a breakpoint variable). 75 | @if $value == string { 76 | // If using 'break-1', 'break-2' etc output the correct breakpoints from map. 77 | @if map-has-key($breakpoints, $break) { 78 | @media screen and (min-width: #{map-get($breakpoints, $break) / 16 * 1em} ) { @content; } 79 | } @else { 80 | @warn "#{$break} is not a set breakpoint variable"; 81 | } 82 | 83 | // If it is a number, use this for the breakpoint. 84 | } @else if $value == number { 85 | // If using other numbers output value in ems either for min, min & max or max width breakpoints. 86 | $query: "all" !default; 87 | @if $break != 0 and $max != 0 { $query: "(min-width: #{$break / 16 * 1em}) and (max-width: #{$max / 16 * 1em})"; } 88 | @else if $break != 0 and $max == 0 { $query: "(min-width: #{$break / 16 * 1em})"; } 89 | @else if $break == 0 and $max != 0 { $query: "(max-width: #{$max / 16 * 1em})"; } 90 | @media #{$query} { @content; } 91 | 92 | } @else { 93 | @warn "#{$break} is not valid to use as a breakpoint"; 94 | } 95 | } 96 | 97 | // Root font-size in %, outputted in correct breakpoints. 98 | @mixin rootsize { 99 | font-size: nth($sizes, 1) / 16 * 100%; 100 | 101 | // Loop through breakpoints. 102 | @for $i from 2 through $breakpoints-limit { 103 | @media screen and (min-width: nth($points, $i) / 16 * 1em ) { 104 | font-size: nth($sizes, $i) / 16 * 100%; 105 | } 106 | } 107 | } 108 | 109 | // Max-widths for typeset containers, outputted in correct breakpoints. 110 | @mixin maxwidth($breakpoint: 0) { 111 | // Type of chosen variables. 112 | $break-value: type-of($breakpoint); 113 | 114 | // If specifying a breakpoint to use (and breakpoint exists). 115 | @if $break-value == number and $breakpoint <= ($breakpoints-limit - 1) and $breakpoint >= 0 { 116 | 117 | max-width: #{nth($max-widths, ($breakpoint + 1)) / nth($sizes, ($breakpoint + 1))}rem; 118 | 119 | } @else if $breakpoint == all { 120 | max-width: #{nth($max-widths, 1) / nth($sizes, 1)}rem; 121 | 122 | // Loop through breakpoints. 123 | @for $i from 2 through $breakpoints-limit { 124 | @media screen and (min-width: nth($points, $i) / 16 * 1em ) { 125 | max-width: #{nth($max-widths, $i) / nth($sizes, $i)}rem; 126 | } 127 | } 128 | } 129 | } 130 | 131 | // Set the measure for single columns, outputted in correct breakpoints. 132 | @mixin measure($breakpoint: 0) { 133 | // Type of chosen variables. 134 | $break-value: type-of($breakpoint); 135 | 136 | // If specifying a breakpoint to use (and breakpoint exists). 137 | @if $break-value == number and $breakpoint <= ($breakpoints-limit - 1) and $breakpoint >= 0 { 138 | 139 | max-width: #{nth($line-widths, ($breakpoint + 1)) / nth($sizes, ($breakpoint + 1))}rem; 140 | 141 | } @else if $breakpoint == all { 142 | max-width: #{nth($line-widths, 1) / nth($sizes, 1)}rem; 143 | 144 | // Loop through breakpoints. 145 | @for $i from 2 through $breakpoints-limit { 146 | @media screen and (min-width: nth($points, $i) / 16 * 1em ) { 147 | max-width: #{nth($line-widths, $i) / nth($sizes, $i)}rem; 148 | } 149 | } 150 | } 151 | } 152 | 153 | // Calculate percentage width of container to get optimal measure for main text columns. 154 | // Defaults to all breakpoints. 155 | // Note: will not output for base breakpoint as this comes from the 'measure' mixin. 156 | @mixin ideal-measure($breakpoint: 0, $gutter: 0, $main: true, $output: max-width) { 157 | // Type of chosen variables. 158 | $break-value: type-of($breakpoint); 159 | 160 | // If specifying a breakpoint to use (and breakpoint exists and is larger than 0). 161 | @if $break-value == number and $breakpoint <= ($breakpoints-limit - 1) and $breakpoint > 0 { 162 | 163 | @if $gutter == small { 164 | $gutter: map-get($gutterwidths, small) * 2 / 1rem; 165 | } @else if $gutter == medium { 166 | $gutter: map-get($gutterwidths, medium) * 2 / 1rem; 167 | } @else if $gutter == large { 168 | $gutter: map-get($gutterwidths, large) * 2 / 1rem; 169 | } @else { 170 | $gutter: 0; 171 | } 172 | 173 | $rootsize: map-get($rootsizes, rootsize-#{$breakpoint}); 174 | $ideal-measure: map-get($measures, measure-#{$breakpoint}); 175 | $gutter-size: ($gutter * $rootsize); 176 | $container-width: map-get($maxwidths, width-#{$breakpoint}); 177 | 178 | $percentage: percentage(($ideal-measure + $gutter-size) / $container-width); 179 | 180 | @if $percentage < 55 { 181 | $percentage: 55%; 182 | } @else if $percentage > 65 { 183 | $percentage: 65%; 184 | } 185 | 186 | @if $main == false { 187 | $percentage: 100 - $percentage; 188 | } 189 | 190 | #{$output}: $percentage; 191 | } 192 | } 193 | 194 | // Value in scale in $modular-scale? 195 | // Used in following fontsize mixin. 196 | @function in-modular-scale($scale, $key) { 197 | $map: map-get($modular-scale, $scale); 198 | $output: map-has-key($map, $key); 199 | @return $output; 200 | } 201 | 202 | // Font-size in rems. Either set per breakpoint or for all. 203 | // Use values as you would for pixels i.e. 16 or use values from the modular scale. 204 | @mixin fontsize($fontsize, $breakpoint: 0) { 205 | // Type of chosen variables. 206 | $font-value: type-of($fontsize); 207 | $break-value: type-of($breakpoint); 208 | 209 | // Check if value exists in scale. 210 | $in-scale: in-modular-scale(scale-0, $fontsize); 211 | 212 | // If specifying a breakpoint to use (and breakpoint exists). 213 | @if $break-value == number and $breakpoint <= ($breakpoints-limit - 1) and $breakpoint >= 0 { 214 | 215 | // If using a number for fontsize. 216 | @if $font-value == number { 217 | font-size: #{$fontsize / nth($sizes, ($breakpoint + 1))}rem; 218 | 219 | // If using a variable from the scale for fontsize. 220 | } @else if $in-scale == true { 221 | $get-scale: map-get($modular-scale, scale-#{$breakpoint}); 222 | $get-size: map-get($get-scale, $fontsize); 223 | 224 | font-size: #{$get-size / nth($sizes, ($breakpoint + 1))}rem; 225 | 226 | } @else { 227 | @warn "#{$fontsize} is not a valid scale variable"; 228 | } 229 | 230 | // If want to use value for all breakpoints. 231 | } @else if $breakpoint == all { 232 | 233 | // If using a number for fontsize. 234 | @if $font-value == number { 235 | font-size: #{$fontsize / nth($sizes, 1)}rem; 236 | 237 | // Loop through breakpoints. 238 | @for $i from 2 through $breakpoints-limit { 239 | @media screen and (min-width: nth($points, $i) / 16 * 1em ) { 240 | font-size: #{$fontsize / nth($sizes, $i)}rem; 241 | } 242 | } 243 | 244 | // If using a variable from the scale for fontsize. 245 | } @else if $in-scale == true { 246 | $get-scale: map-get($modular-scale, scale-0); 247 | $get-size: map-get($get-scale, $fontsize); 248 | font-size: #{$get-size / nth($sizes, 1)}rem; 249 | 250 | // Loop through breakpoints. 251 | @for $i from 2 through $breakpoints-limit { 252 | $get-scale: map-get($modular-scale, scale-#{$i - 1}); 253 | $get-size: map-get($get-scale, $fontsize); 254 | 255 | @media screen and (min-width: nth($points, $i) / 16 * 1em ) { 256 | font-size: #{$get-size / nth($sizes, $i)}rem; 257 | } 258 | } 259 | 260 | } @else { 261 | @warn "#{$fontsize} is not a valid scale variable"; 262 | } 263 | 264 | } @else { 265 | @warn "#{$breakpoint} is not valid to use as a breakpoint"; 266 | } 267 | } 268 | 269 | // Advanced baseline magic. 270 | // ! Read the README to help understand what is going on here. 271 | // Parts based on https://gist.github.com/razwan/10662500 272 | @mixin baseline($fontsize, $font, $lineheight: 2, $below: 2, $breakpoint: 0) { 273 | // Type of chosen variables. 274 | $font-value: type-of($fontsize); 275 | $break-value: type-of($breakpoint); 276 | 277 | // Cap height 278 | $cap-height: map-get($font, cap-height); 279 | 280 | // Check if value exists in scale. 281 | $in-scale: in-modular-scale(scale-0, $fontsize); 282 | 283 | // Set the line-height. 284 | line-height: #{$lineheight}rem; 285 | 286 | // If specifying a breakpoint to use (and breakpoint exists). 287 | @if $break-value == number and $breakpoint <= ($breakpoints-limit - 1) and $breakpoint >= 0 { 288 | 289 | // If using a number for fontsize. 290 | @if $font-value == number { 291 | $rootsize: nth($sizes, ($breakpoint + 1)); 292 | $baseline-shift: #{($fontsize / 2 * (($lineheight * $rootsize / $fontsize) - $cap-height)) / $rootsize + 0.00001}; 293 | $baseline-push: #{$below - (($fontsize / 2 * (($lineheight * $rootsize / $fontsize) - $cap-height)) / $rootsize + 0.00001)}; 294 | 295 | margin-bottom: #{$baseline-push}rem; 296 | padding-top: #{$baseline-shift}rem; 297 | 298 | // If using a variable from the scale for fontsize. 299 | } @else if $in-scale == true { 300 | $get-scale: map-get($modular-scale, scale-#{$breakpoint}); 301 | $get-size: map-get($get-scale, $fontsize); 302 | $rootsize: nth($sizes, ($breakpoint + 1)); 303 | 304 | $baseline-shift: #{($get-size / 2 * (($lineheight * $rootsize / $get-size) - $cap-height)) / $rootsize + 0.00001}; 305 | $baseline-push: #{$below - (($get-size / 2 * (($lineheight * $rootsize / $get-size) - $cap-height)) / $rootsize + 0.00001)}; 306 | 307 | margin-bottom: #{$baseline-push}rem; 308 | padding-top: #{$baseline-shift}rem; 309 | 310 | } @else { 311 | @warn "#{$fontsize} is not a valid scale variable"; 312 | } 313 | 314 | // If want to use value for all breakpoints. 315 | } @else if $breakpoint == all { 316 | 317 | // If using a number for fontsize. 318 | @if $font-value == number { 319 | $rootsize: nth($sizes, 1); 320 | $baseline-shift: #{($fontsize / 2 * (($lineheight * $rootsize / $fontsize) - $cap-height)) / $rootsize + 0.00001}; 321 | $baseline-push: #{$below - (($fontsize / 2 * (($lineheight * $rootsize / $fontsize) - $cap-height)) / $rootsize + 0.00001)}; 322 | 323 | margin-bottom: #{$baseline-push}rem; 324 | padding-top: #{$baseline-shift}rem; 325 | 326 | // Loop through breakpoints. 327 | @for $i from 2 through $breakpoints-limit { 328 | $rootsize: nth($sizes, $i); 329 | $baseline-shift: #{($fontsize / 2 * (($lineheight * $rootsize / $fontsize) - $cap-height)) / $rootsize + 0.00001}; 330 | $baseline-push: #{$below - (($fontsize / 2 * (($lineheight * $rootsize / $fontsize) - $cap-height)) / $rootsize + 0.00001)}; 331 | 332 | @media screen and (min-width: nth($points, $i) / 16 * 1em ) { 333 | margin-bottom: #{$baseline-push}rem; 334 | padding-top: #{$baseline-shift}rem; 335 | } 336 | } 337 | 338 | // If using a variable from the scale for fontsize. 339 | } @else if $in-scale == true { 340 | $get-scale: map-get($modular-scale, scale-0); 341 | $get-size: map-get($get-scale, $fontsize); 342 | $rootsize: nth($sizes, 1); 343 | 344 | $baseline-shift: #{($get-size / 2 * (($lineheight * $rootsize / $get-size) - $cap-height)) / $rootsize + 0.00001}; 345 | $baseline-push: #{$below - (($get-size / 2 * (($lineheight * $rootsize / $get-size) - $cap-height)) / $rootsize + 0.00001)}; 346 | 347 | margin-bottom: #{$baseline-push}rem; 348 | padding-top: #{$baseline-shift}rem; 349 | 350 | // Loop through breakpoints. 351 | @for $i from 2 through $breakpoints-limit { 352 | $get-scale: map-get($modular-scale, scale-#{$i - 1}); 353 | $get-size: map-get($get-scale, $fontsize); 354 | $rootsize: nth($sizes, $i); 355 | 356 | $baseline-shift: #{($get-size / 2 * (($lineheight * $rootsize / $get-size) - $cap-height)) / $rootsize + 0.00001}; 357 | $baseline-push: #{$below - (($get-size / 2 * (($lineheight * $rootsize / $get-size) - $cap-height)) / $rootsize + 0.00001)}; 358 | 359 | @media screen and (min-width: nth($points, $i) / 16 * 1em ) { 360 | margin-bottom: #{$baseline-push}rem; 361 | padding-top: #{$baseline-shift}rem; 362 | } 363 | } 364 | 365 | } @else { 366 | @warn "#{$fontsize} is not a valid scale variable"; 367 | } 368 | 369 | } @else { 370 | @warn "#{$breakpoint} is not valid to use as a breakpoint"; 371 | } 372 | } 373 | 374 | // Set fontsize and baseline at once. Mix of fontsize and baseline mixin. 375 | @mixin sassline($fontsize, $font, $lineheight: 2, $below: 2, $breakpoint: 0) { 376 | $font-value: type-of($fontsize); 377 | $break-value: type-of($breakpoint); 378 | $cap-height: map-get($font, cap-height); 379 | $in-scale: in-modular-scale(scale-0, $fontsize); 380 | 381 | line-height: #{$lineheight}rem; 382 | 383 | @if $break-value == number and $breakpoint <= ($breakpoints-limit - 1) and $breakpoint >= 0 { 384 | 385 | @if $font-value == number { 386 | $rootsize: nth($sizes, ($breakpoint + 1)); 387 | $baseline-shift: #{($fontsize / 2 * (($lineheight * $rootsize / $fontsize) - $cap-height)) / $rootsize + 0.00001}; 388 | $baseline-push: #{$below - (($fontsize / 2 * (($lineheight * $rootsize / $fontsize) - $cap-height)) / $rootsize + 0.00001)}; 389 | font-size: #{$fontsize / nth($sizes, ($breakpoint + 1))}rem; 390 | margin-bottom: #{$baseline-push}rem; 391 | padding-top: #{$baseline-shift}rem; 392 | 393 | } @else if $in-scale == true { 394 | $get-scale: map-get($modular-scale, scale-#{$breakpoint}); 395 | $get-size: map-get($get-scale, $fontsize); 396 | $rootsize: nth($sizes, ($breakpoint + 1)); 397 | $baseline-shift: #{($get-size / 2 * (($lineheight * $rootsize / $get-size) - $cap-height)) / $rootsize + 0.00001}; 398 | $baseline-push: #{$below - (($get-size / 2 * (($lineheight * $rootsize / $get-size) - $cap-height)) / $rootsize + 0.00001)}; 399 | font-size: #{$get-size / nth($sizes, ($breakpoint + 1))}rem; 400 | margin-bottom: #{$baseline-push}rem; 401 | padding-top: #{$baseline-shift}rem; 402 | 403 | } @else { 404 | @warn "#{$fontsize} is not a valid scale variable"; 405 | } 406 | 407 | } @else if $breakpoint == all { 408 | 409 | @if $font-value == number { 410 | $rootsize: nth($sizes, 1); 411 | $baseline-shift: #{($fontsize / 2 * (($lineheight * $rootsize / $fontsize) - $cap-height)) / $rootsize + 0.00001}; 412 | $baseline-push: #{$below - (($fontsize / 2 * (($lineheight * $rootsize / $fontsize) - $cap-height)) / $rootsize + 0.00001)}; 413 | font-size: #{$fontsize / nth($sizes, 1)}rem; 414 | margin-bottom: #{$baseline-push}rem; 415 | padding-top: #{$baseline-shift}rem; 416 | 417 | @for $i from 2 through $breakpoints-limit { 418 | $rootsize: nth($sizes, $i); 419 | $baseline-shift: #{($fontsize / 2 * (($lineheight * $rootsize / $fontsize) - $cap-height)) / $rootsize + 0.00001}; 420 | $baseline-push: #{$below - (($fontsize / 2 * (($lineheight * $rootsize / $fontsize) - $cap-height)) / $rootsize + 0.00001)}; 421 | @media screen and (min-width: nth($points, $i) / 16 * 1em ) { 422 | font-size: #{$fontsize / nth($sizes, $i)}rem; 423 | margin-bottom: #{$baseline-push}rem; 424 | padding-top: #{$baseline-shift}rem; 425 | } 426 | } 427 | 428 | } @else if $in-scale == true { 429 | $get-scale: map-get($modular-scale, scale-0); 430 | $get-size: map-get($get-scale, $fontsize); 431 | $rootsize: nth($sizes, 1); 432 | $baseline-shift: #{($get-size / 2 * (($lineheight * $rootsize / $get-size) - $cap-height)) / $rootsize + 0.00001}; 433 | $baseline-push: #{$below - (($get-size / 2 * (($lineheight * $rootsize / $get-size) - $cap-height)) / $rootsize + 0.00001)}; 434 | font-size: #{$get-size / nth($sizes, 1)}rem; 435 | margin-bottom: #{$baseline-push}rem; 436 | padding-top: #{$baseline-shift}rem; 437 | 438 | @for $i from 2 through $breakpoints-limit { 439 | $get-scale: map-get($modular-scale, scale-#{$i - 1}); 440 | $get-size: map-get($get-scale, $fontsize); 441 | $rootsize: nth($sizes, $i); 442 | $baseline-shift: #{($get-size / 2 * (($lineheight * $rootsize / $get-size) - $cap-height)) / $rootsize + 0.00001}; 443 | $baseline-push: #{$below - (($get-size / 2 * (($lineheight * $rootsize / $get-size) - $cap-height)) / $rootsize + 0.00001)}; 444 | @media screen and (min-width: nth($points, $i) / 16 * 1em ) { 445 | font-size: #{$get-size / nth($sizes, $i)}rem; 446 | margin-bottom: #{$baseline-push}rem; 447 | padding-top: #{$baseline-shift}rem; 448 | } 449 | } 450 | 451 | } @else { 452 | @warn "#{$fontsize} is not a valid scale variable"; 453 | } 454 | 455 | } @else { 456 | @warn "#{$breakpoint} is not valid to use as a breakpoint"; 457 | } 458 | } 459 | 460 | // Clearfix. 461 | @mixin clearfix { 462 | &:before, &:after{ 463 | display: table; 464 | content: ""; 465 | } 466 | &:after{ 467 | clear: both; 468 | } 469 | } 470 | -------------------------------------------------------------------------------- /src/app/styles/partials/_reset.scss: -------------------------------------------------------------------------------- 1 | // Reset 2 | // --------------------------------------- 3 | 4 | // Reset all the things 5 | * { -moz-box-sizing: border-box; box-sizing: border-box; } 6 | html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video { margin: 0; padding: 0; border: 0; font-size: 100%; font: inherit; vertical-align: baseline; } 7 | article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { display: block; } 8 | html, body { height: 100%; } 9 | a img { border: none; } 10 | blockquote { quotes: none; } 11 | blockquote:before, blockquote:after { content: ''; content: none; } 12 | table { border-collapse: collapse; border-spacing: 0; } 13 | caption, th, td { text-align: left; font-weight: normal; vertical-align: middle; } -------------------------------------------------------------------------------- /src/app/styles/partials/_variables.scss: -------------------------------------------------------------------------------- 1 | // SCSS variables 2 | // --------------------------------------- 3 | 4 | // Note: For the following Sass maps enter values as if they would be px units. 5 | 6 | // Breakpoint sizes from px to ems. Add more values here to add more breakpoints. 7 | // Change names if you prefer, it wont break the mixin as long as they are strings not just numbers. 8 | $breakpoints: ( 9 | break-0: 0, // 0px Mobile first 10 | break-1: 640, // 640px ~ Small tablet up 11 | break-2: 800, // 800px ~ Large tablet up 12 | break-3: 1024, // 1024px ~ Desktop up 13 | break-4: 1600 // 1600px ~ Large desktop up 14 | ); 15 | 16 | // Root font-sizes for each breakpoint. Set to half desired line-height of body text. 17 | // ! Make sure to have as many sizes as breakpoints above. 18 | $rootsizes: ( 19 | rootsize-0: 12, // 24px line-height body text 20 | rootsize-1: 14, // 28px line-height body text 21 | rootsize-2: 15, // 30px line-height body text 22 | rootsize-3: 17, // 34px line-height body text 23 | rootsize-4: 19 // 38px line-height body text 24 | ); 25 | 26 | // Set the optimum line-length for your text (based on typeface). 27 | // Aim for 75–100 characters a line when possible, at smaller sizes type size is more important. 28 | // ! Make sure to have as many widths as breakpoints above. 29 | // Note: this was 'maxwidths' in previous versions. 30 | $measures: ( 31 | measure-0: 500, // 500px wide 32 | measure-1: 550, // 550px wide 33 | measure-2: 600, // 600px wide 34 | measure-3: 680, // 680px wide 35 | measure-4: 750 // 750px wide 36 | ); 37 | 38 | // Set the max-widths for containers (based on design). 39 | // ! Make sure to have as many widths as breakpoints above. 40 | $maxwidths: ( 41 | width-0: 500, // 500px wide 42 | width-1: 600, // 600px wide 43 | width-2: 800, // 800px wide 44 | width-3: 1100, // 110px wide 45 | width-4: 1300 // 1300px wide 46 | ); 47 | 48 | // Gutter widths 49 | $gutterwidths: ( 50 | small: 1rem, 51 | medium: 2rem, 52 | large: 4rem 53 | ); 54 | 55 | // Add typefaces here. 56 | // Add weight and style details too. 57 | // ! Set cap height to set to the baseline. 58 | 59 | //TODO: add hosted fonts/include font files 60 | 61 | $bodytype: ( 62 | font-family: "'Source Sans Pro','Avenir Next', AvenirNext", 63 | regular: 400, 64 | bold: 700, 65 | italic: italic, 66 | cap-height: 0.62 67 | ); 68 | 69 | $headingtype: ( 70 | font-family: "'Source Sans Pro','Avenir Next', AvenirNext", 71 | text-transform: uppercase, 72 | regular: 400, 73 | bold: 700, 74 | cap-height: 0.30 75 | ); 76 | 77 | $monospacetype: ( 78 | font-family: "'Source Code Pro', Menlo, monospace", 79 | regular: 400, 80 | cap-height: 0.68 81 | ); 82 | 83 | // Basic Colors 84 | // --------------------------------------- 85 | $color-bg: #242930; 86 | $color-dark-light: #343434; 87 | $color-dark-lighter: #444; 88 | $color-dark-lightest: #777; 89 | $color-body: #808386; 90 | $color-white: #FFFFFF; 91 | 92 | 93 | // Modular scale 94 | // --------------------------------------- 95 | 96 | // Setting responsive modular-scales. Use appropriate scales for viewport sizes. 97 | $modular-scale: (scale-0: (alpha: 28, beta: 25, gamma: 22.4, delta: 20, epsilon: 17.9, zeta: 16, eta: 14.3, theta: 12.8, iota: 11.5), scale-1: (alpha: 30, beta: 26.6, gamma: 24, delta: 21.3, epsilon: 19.2, zeta: 17, eta: 15.3, theta: 13.6, iota: 12.8), scale-2: (alpha: 32, beta: 28.1, gamma: 25.6, delta: 22.5, epsilon: 20.5, zeta: 18, eta: 16.3, theta: 14.4, iota: 13.1), scale-3: (alpha: 40, beta: 35.5, gamma: 30, delta: 26.7, epsilon: 22.5, zeta: 20, eta: 16.9, theta: 15, iota: 12.7), scale-4: (alpha: 50, beta: 43.9, gamma: 35.3, delta: 31.1, epsilon: 25, zeta: 22, eta: 17.6, theta: 15.6, iota: 12.5)); 98 | -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carolineartz/learning-box-model/44333252e3a7cab2cfd76c8255ee59deded18e9a/src/favicon.ico -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | cssBoxModel 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 22 | 23 |
24 | 25 | 26 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /src/tests/main.controller.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('Unit: MainCtrl', function () { 4 | beforeEach(module('cssBoxModel')); 5 | 6 | var ctrl, scope; 7 | // inject the $controller and $rootScope services 8 | // in the beforeEach block 9 | beforeEach(inject(function ($controller, $rootScope) { 10 | // Create a new scope that's a child of the $rootScope 11 | scope = $rootScope.$new(); 12 | // Create the controller 13 | ctrl = $controller('MainCtrl', { 14 | $scope: scope 15 | }); 16 | })); 17 | 18 | it('should create $scope.greeting when calling sayHello', 19 | function () { 20 | expect(scope.greeting).toBeUndefined(); 21 | scope.sayHello(); 22 | expect(scope.greeting).toEqual("Hello Caroline"); 23 | }); 24 | }) 25 | --------------------------------------------------------------------------------