├── LICENSE.md ├── README.md ├── index.js ├── package.json ├── server.js └── test └── index.js /LICENSE.md: -------------------------------------------------------------------------------- 1 | 2 | # The MIT License (MIT) 3 | Copyright (c) 2016 Brent Jackson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Space 3 | 4 | Functional CSS white space utility microservice 5 | 6 | https://space.now.sh 7 | 8 | ## Usage 9 | 10 | Although this microservice can be hotlinked to, 11 | the delay in server response will add a performance dent to your site. 12 | Instead, it's recommended to either copy the results from a browser or use cURL. 13 | 14 | ```sh 15 | curl https://space.now.sh > space.css 16 | ``` 17 | 18 | ## Query params 19 | 20 | The CSS output can be customized using the following parameters. 21 | 22 | ### `space` 23 | 24 | Array of numbers in pixels for the white space scale. 25 | 26 | E.g. `/?space=6,12,24,48` 27 | 28 | ### `breakpoints` 29 | 30 | Array of numbers in ems for the breakpoints 31 | 32 | E.g. `/?breakpoints=48,64` 33 | 34 | For no breakpoints, pass a null value: `/?breakpoints=` 35 | 36 | ### `properties` 37 | 38 | Array of CSS property strings to create rules for. 39 | 40 | E.g. `/?properties=margin,padding` 41 | 42 | ## Quick Links 43 | 44 | - [Non-responsive version](https://space.now.sh/?breakpoints=) 45 | - [Small](https://space.now.sh/?breakpoints=&space=8,16,32) 46 | - [Duodecimal scale](https://space.now.sh/?space=6,12,24,48) 47 | - [Margin only](https://space.now.sh/?properties=margin,margin-top,margin-right,margin-bottom,margin-left) 48 | - [Padding only](https://space.now.sh/?properties=padding,padding-top,padding-right,padding-bottom,padding-left) 49 | 50 | 51 | [MIT License](LICENSE.md) 52 | 53 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 2 | const abbr = str => str.split('-').map(s => s.charAt(0)).join('') 3 | 4 | const createPrefixes = length => { 5 | const vals = [ 6 | 'md', 'lg', 'sm', 'xl', 'xs', 'xxl', 'xxs' 7 | ] 8 | 9 | const prefixes = [] 10 | 11 | Array.from({ length }) 12 | .map((n, i) => i) 13 | .forEach(s => { 14 | if (s % 2) { 15 | prefixes.push(vals[s]) 16 | } else { 17 | prefixes.unshift(vals[s]) 18 | } 19 | }) 20 | 21 | return prefixes 22 | } 23 | 24 | const getPrefix = length => i => { 25 | const prefixes = createPrefixes(length) 26 | return prefixes[i] 27 | } 28 | 29 | const createRule = (prefix) => property => (step, i) => { 30 | const selector = prefix 31 | ? `${prefix}-${abbr(property)}${i}` 32 | : `${abbr(property)}${i}` 33 | return `.${selector}{${property}:${step}px}` 34 | } 35 | 36 | const createMediaRule = breakpoint => rules => { 37 | return `@media screen and (min-width:${breakpoint}em){${rules.join('')}}` 38 | } 39 | 40 | const space = ({ 41 | space = [ 42 | 8, 43 | 16, 44 | 32, 45 | 48, 46 | 64, 47 | 96 48 | ], 49 | breakpoints = [ 50 | 40, 51 | 52, 52 | 64 53 | ], 54 | properties = [ 55 | 'margin', 56 | 'margin-top', 57 | 'margin-right', 58 | 'margin-bottom', 59 | 'margin-left', 60 | 'padding', 61 | 'padding-top', 62 | 'padding-right', 63 | 'padding-bottom', 64 | 'padding-left', 65 | ] 66 | } = {}) => { 67 | const rules = [] 68 | 69 | if (space[0] !== 0) { 70 | space.unshift(0) 71 | } 72 | 73 | const prefix = getPrefix(breakpoints.length) 74 | const breakpointRules = breakpoints 75 | .filter(b => !isNaN(parseFloat(b))) 76 | .map((b, i) => ({ 77 | breakpoint: b, 78 | func: createRule(prefix(i)) 79 | })) 80 | 81 | breakpointRules.unshift({ 82 | breakpoint: null, 83 | func: createRule(null) 84 | }) 85 | 86 | breakpointRules.forEach(({ breakpoint, func }) => { 87 | const arr = [] 88 | const propertyRules = properties.map((p, i) => func(p)) 89 | 90 | propertyRules.forEach(p => { 91 | space.forEach((step, i) => { 92 | arr.push(p(step, i)) 93 | }) 94 | }) 95 | 96 | if (breakpoint) { 97 | rules.push(createMediaRule(breakpoint)(arr)) 98 | return 99 | } 100 | 101 | arr.forEach(r => rules.push(r)) 102 | }) 103 | 104 | const css = rules.join('') 105 | 106 | return css 107 | } 108 | 109 | module.exports = space 110 | 111 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "space", 3 | "private": true, 4 | "version": "1.0.0", 5 | "description": "Functional CSS white space utility microservice", 6 | "main": "server.js", 7 | "scripts": { 8 | "start": "./node_modules/micro/bin/micro -p 3000", 9 | "test": "ava" 10 | }, 11 | "author": "Brent Jackson", 12 | "license": "MIT", 13 | "devDependencies": { 14 | "ava": "^0.16.0" 15 | }, 16 | "dependencies": { 17 | "micro": "^6.1.0" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | 2 | const url = require('url') 3 | const space = require('./index') 4 | 5 | const getOptions = query => Object.keys(query).reduce((obj, b) => { 6 | obj[b] = query[b].split(',') 7 | .map(v => { 8 | const num = parseFloat(v) 9 | return isNaN(num) ? v : num 10 | }) 11 | return obj 12 | }, {}) 13 | 14 | module.exports = async function (req, res) { 15 | const { query } = url.parse(req.url, true) 16 | const options = getOptions(query) 17 | const css = space(options) 18 | 19 | return css 20 | } 21 | 22 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | 2 | import test from 'ava' 3 | import space from '../index' 4 | 5 | test('returns a string', t => { 6 | const css = space() 7 | t.is(typeof css, 'string') 8 | }) 9 | 10 | --------------------------------------------------------------------------------