Repository: jxnblk/gravitons Branch: master Commit: 99d2d86c3b12 Files: 18 Total size: 16.4 KB Directory structure: gitextract_bsa5rbth/ ├── .gitignore ├── .npmignore ├── .travis.yml ├── README.md ├── bin/ │ └── gravitons.js ├── docs/ │ ├── entry.js │ ├── index.html │ ├── logo.js │ ├── stats.js │ └── stats.json ├── index.js ├── lib/ │ ├── flatten-array.js │ ├── get-initials.js │ ├── kebab.js │ ├── number-to-pixel.js │ └── styles.js ├── package.json └── test/ └── index.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ docs/bundle.js ================================================ FILE: .npmignore ================================================ docs ================================================ FILE: .travis.yml ================================================ language: node_js node_js: - 6.2 script: - npm test ================================================ FILE: README.md ================================================ # gravitons Virtually massless CSS layout microlibrary – http://jxnblk.com/gravitons [![Build Status](https://travis-ci.org/jxnblk/gravitons.svg?branch=master)](https://travis-ci.org/jxnblk/gravitons) ```sh npm i -g gravitons ``` ![gravitons](https://cloud.githubusercontent.com/assets/3451712/17651212/1b8de4c0-6230-11e6-9b15-90e659688650.gif) ```sh gravitons > base.css ``` Returns the following to stdout: ```css /*! gravitons */ .h0{font-size:48px} .h1{font-size:32px} .h2{font-size:24px} .h3{font-size:20px} .h4{font-size:16px} .h5{font-size:14px} .h6{font-size:12px} .m0{margin:0} .m1{margin:8px} .m2{margin:16px} .m3{margin:32px} .m4{margin:64px} .mt0{margin-top:0} .mt1{margin-top:8px} .mt2{margin-top:16px} .mt3{margin-top:32px} .mt4{margin-top:64px} .mr0{margin-right:0} .mr1{margin-right:8px} .mr2{margin-right:16px} .mr3{margin-right:32px} .mr4{margin-right:64px} .mb0{margin-bottom:0} .mb1{margin-bottom:8px} .mb2{margin-bottom:16px} .mb3{margin-bottom:32px} .mb4{margin-bottom:64px} .ml0{margin-left:0} .ml1{margin-left:8px} .ml2{margin-left:16px} .ml3{margin-left:32px} .ml4{margin-left:64px} .p0{padding:0} .p1{padding:8px} .p2{padding:16px} .p3{padding:32px} .p4{padding:64px} .pt0{padding-top:0} .pt1{padding-top:8px} .pt2{padding-top:16px} .pt3{padding-top:32px} .pt4{padding-top:64px} .pr0{padding-right:0} .pr1{padding-right:8px} .pr2{padding-right:16px} .pr3{padding-right:32px} .pr4{padding-right:64px} .pb0{padding-bottom:0} .pb1{padding-bottom:8px} .pb2{padding-bottom:16px} .pb3{padding-bottom:32px} .pb4{padding-bottom:64px} .pl0{padding-left:0} .pl1{padding-left:8px} .pl2{padding-left:16px} .pl3{padding-left:32px} .pl4{padding-left:64px} .db{display:block} .dib{display:inline-block} .di{display:inline} .dt{display:table} .dtr{display:table-row} .dtc{display:table-cell} .df{display:flex} .dif{display:inline-flex} .fl{float:left} .fr{float:right} .oh{overflow:hidden} .cf:after{content:"";display:block;clear:both} .x0{width:0} .x1{width:8.333333333333332%} .x2{width:16.666666666666664%} .x3{width:25%} .x4{width:33.33333333333333%} .x5{width:41.66666666666667%} .x6{width:50%} .x7{width:58.333333333333336%} .x8{width:66.66666666666666%} .x9{width:75%} .x10{width:83.33333333333334%} .x11{width:91.66666666666666%} .x12{width:100%} ``` MIT License ================================================ FILE: bin/gravitons.js ================================================ #! /usr/bin/env node const gravitons = require('..')() process.stdout.write(gravitons) ================================================ FILE: docs/entry.js ================================================ const h = require('h0').default const gravitons = require('..')() const stats = require('./stats.json') const logo = require('./logo') const demoCss = ` *{box-sizing:border-box} body{ font-family:-apple-system,BlinkMacSystemFont,sans-serif; font-family: Menlo, monospace; line-height:1.5; margin:0; color:#111; } ` const blue = '#05a' const div = h('div') const h1 = h('h1')({ class: 'h3 mt4 mb1' }) const h2 = h('h2')({ class: 'h3 mt4 mb1' }) const p = h('p') const pre = h('pre')({ style: { fontFamily: 'Menlo, monospace', lineHeight: 2, fontSize: 14, overflowX: 'scroll', paddingLeft: 16, marginBottom: 32, borderLeft: '4px solid rgba(0,0,0,.0625)' } }) const ul = h('ul') const li = h('li') const link = h('a')({ style: { color: blue } }) const btn = h('a')({ class: 'dib p1', style: { color: 'white', backgroundColor: 'blue', border: 0, WebkitAppearance: 'none', } }) const blockquote = h('blockquote')({ style: { maxWidth: '42em' }, class: 'h2 m0 mt4 mb4' }) const tree = div({ class: 'p3' })( h('style')(demoCss + gravitons.replace(/\n/g, '')), h('header')({})( div({ class: 'mt4 mb4' })( logo() ), h1('Gravitons'), p('Virtually massless CSS layout microlibrary'), div( link({ href: 'https://github.com/jxnblk/gravitons', class: 'mr2' })('GitHub'), link({ href: 'https://npmjs.com/package/gravitons' })('npm') ), ), p({ style: { maxWidth: '42em' }, class: 'h2 mt4 mb4' })( 'Gravitons is an extremely lightweight suite of CSS layout utilities based on modular scales and inspired by the ', link({ href: 'http://en.wikipedia.org/wiki/Unix_philosophy' })('Unix Philosophy') ), pre('npm i -g gravitons'), pre('gravitons > base.css'), pre(`${stats.humanizedGzipSize} gzipped - ${stats.rules.total} rules - ${stats.selectors.total} selectors - ${stats.declarations.total} declarations`), h2('Features'), ul( li('Roughly .5KB gzipped'), li('Shorthand naming convention'), li('Quick to internalize'), li('No colors'), li('No media queries'), li('No monolithic component styles') ), h2('CSS'), pre(gravitons), blockquote('The graviton is a hypothetical elementary particle that mediates the force of gravitation in the framework of quantum field theory'), div({ class: 'mt4 mb4' })( h2('Related'), link({ href: 'http://tachyons.io', class: 'mr2' })('Tachyons'), link({ href: 'http://basscss.com' })('Basscss') ), h('footer')({ class: 'mt4 mb4' })( link({ href: 'https://github.com/jxnblk/gravitons', class: 'mr2' })('GitHub'), link({ href: 'https://npmjs.com/package/gravitons', class: 'mr2' })('npm'), link({ href: 'http://jxnblk.com' })('Made by Jxnblk') ) ) if (typeof app === 'undefined') { const app = document.createElement('div') document.body.appendChild(app) app.appendChild(tree) } else { app.appendChild(tree) } ================================================ FILE: docs/index.html ================================================ Gravitons
================================================ FILE: docs/logo.js ================================================ const h = require('h0').default const logo = () => { const size = 256 const width = 160 // Angle const a = 36 const a1 = 90 - a const a2 = 180 - a // Radii const r0 = size * 0.5625 const r1 = size * 0.4375 const r2 = size * .375 const r3 = size * .3125 const r4 = size * .25 // Offsets const o0 = size/2 - r0 const o1 = size/2 - r1 const o2 = size/2 - r2 const o3 = size/2 - r3 const o4 = size/2 - r4 // Diagonal line stroke width const w = 4 const wy = Math.cos(90-a) * w const wx = Math.sin(90-a) * w // Calculate x coordinate with radius and angle const rx = (r, a) => r + r * Math.cos(Math.PI * a/180) // Calculate y coordinate with radius and angle const ry = (r, a) => r + r * Math.sin(Math.PI * a/180) const circle = [ 'M', o2 + rx(r2, -a), o2 + ry(r2, -a), 'A', r2, r2, '0 1 0', o2 + rx(r2, a), o2 + ry(r2, a), 'L', o3 + rx(r3, a), o3 + ry(r3, a), 'A', r3, r3, '1 1 1', o3 + rx(r3, -a), o3 + ry(r3, -a), 'z', ].join(' ') const diagonal = [ 'M', wx + o0 + rx(r0, a), -wy + o0 + ry(r0, a), 'L', -wx + o0 + rx(r0, a), wy + o0 + ry(r0, a), 'L', -wx + o4 + rx(r4, -a2), wy + o4 + ry(r4, -a2), 'L', wx + o4 + rx(r4, -a2), -wy + o4 + ry(r4, -a2), 'z', 'M', wx + o1 + rx(r1, -a2), -wy + o1 + ry(r1, -a2), 'L', -wx + o1 + rx(r1, -a2), wy + o1 + ry(r1, -a2), 'L', -wx + o0 + rx(r0, -a2), wy + o0 + ry(r0, -a2), 'L', wx + o0 + rx(r0, -a2), -wy + o0 + ry(r0, -a2), 'z' ].join(' ') const css = ` .Logo-particle-1, .Logo-particle-2 { animation-name: spin; animation-timing-function: linear; animation-iteration-count: infinite; } .Logo-particle-1 { transform-origin: 50% 50%; animation-duration: 1s; } .Logo-particle-2 { transform-origin: 50% 50%; animation-duration: 1.25s; animation-direction: reverse; } @keyframes spin { from { transform: rotate(0) } to { transform: rotate(360deg) } } ` const svg = (` `) const div = h('div')() div.innerHTML = svg return h('div')( h('style')(css), div ) } module.exports = logo ================================================ FILE: docs/stats.js ================================================ const fs = require('fs') const path = require('path') const cssstats = require('cssstats') const gravitons = require('..')() const stats = cssstats(gravitons) fs.writeFileSync(path.join(__dirname, 'stats.json'), JSON.stringify(stats)) ================================================ FILE: docs/stats.json ================================================ {"size":1851,"gzipSize":554,"humanizedSize":"2kB","humanizedGzipSize":"554B","rules":{"total":82,"size":{"graph":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1],"max":3,"average":1.024390243902439}},"selectors":{"total":82,"type":0,"class":82,"id":0,"pseudoClass":0,"pseudoElement":1,"values":[".h0",".h1",".h2",".h3",".h4",".h5",".h6",".m0",".m1",".m2",".m3",".m4",".mt0",".mt1",".mt2",".mt3",".mt4",".mr0",".mr1",".mr2",".mr3",".mr4",".mb0",".mb1",".mb2",".mb3",".mb4",".ml0",".ml1",".ml2",".ml3",".ml4",".p0",".p1",".p2",".p3",".p4",".pt0",".pt1",".pt2",".pt3",".pt4",".pr0",".pr1",".pr2",".pr3",".pr4",".pb0",".pb1",".pb2",".pb3",".pb4",".pl0",".pl1",".pl2",".pl3",".pl4",".db",".dib",".di",".dt",".dtr",".dtc",".df",".dif",".fl",".fr",".oh",".cf:after",".x0",".x1",".x2",".x3",".x4",".x5",".x6",".x7",".x8",".x9",".x10",".x11",".x12"],"specificity":{"max":11,"average":10.012195121951219}},"declarations":{"total":84,"properties":{"font-size":["48px","32px","24px","20px","16px","14px","12px"],"margin":["0","8px","16px","32px","64px"],"margin-top":["0","8px","16px","32px","64px"],"margin-right":["0","8px","16px","32px","64px"],"margin-bottom":["0","8px","16px","32px","64px"],"margin-left":["0","8px","16px","32px","64px"],"padding":["0","8px","16px","32px","64px"],"padding-top":["0","8px","16px","32px","64px"],"padding-right":["0","8px","16px","32px","64px"],"padding-bottom":["0","8px","16px","32px","64px"],"padding-left":["0","8px","16px","32px","64px"],"display":["block","inline-block","inline","table","table-row","table-cell","flex","inline-flex","block"],"float":["left","right"],"overflow":["hidden"],"content":["\"\""],"clear":["both"],"width":["0","8.333333333333332%","16.666666666666664%","25%","33.33333333333333%","41.66666666666667%","50%","58.333333333333336%","66.66666666666666%","75%","83.33333333333334%","91.66666666666666%","100%"]}},"mediaQueries":{"total":0,"unique":0,"values":[],"contents":[]}} ================================================ FILE: index.js ================================================ const kebab = require('./lib/kebab') const numberToPixel = require('./lib/number-to-pixel') const getInitials = require('./lib/get-initials') const flattenArray = require('./lib/flatten-array') const styles = require('./lib/styles') const isArr = n => Array.isArray(n) const isStr = n => typeof n === 'string' const isObj = n => typeof n === 'object' && n !== null const createRule = sel => prop => val => ( `.${sel}{${prop}:${numberToPixel(val)}}` ) const createComplexRule = sel => style => { const decs = Object.keys(style).map(key => ( `${kebab(key)}:${style[key]}` )) return `.${sel}{${decs.join(';')}}` } const getScaledSelector = sel => val => i => { if (typeof val === 'number') { return sel + i } return sel + getInitials(val) } const createScaledRules = values => sel => prop => ( values.map((val, i) => ( createRule(getScaledSelector(sel)(val)(i))(prop)(val) )) ) const createDimensionalRules = props => values => ( props.map(prop => ( createScaledRules(values)(getInitials(prop))(prop) )).reduce(flattenArray) ) const createStylesheet = (options = {}) => { const rules = styles.map(style => { const { sel, prop, val, decs } = style if (isArr(prop) && isArr(val)) { return createDimensionalRules(prop)(val) } if (isStr(prop) && isArr(val)) { return createScaledRules(val)(sel)(prop) } if (isObj(decs)) { return createComplexRule(sel)(decs) } return createRule(sel)(prop)(val) }).reduce(flattenArray) const css = `/*! gravitons */\n` + rules.join('\n') + '\n\n' return css } module.exports = createStylesheet ================================================ FILE: lib/flatten-array.js ================================================ const flattenArray = (a = [], b) => { if (Array.isArray(b)) return [...a, ...b] return [...a, b] } module.exports = flattenArray ================================================ FILE: lib/get-initials.js ================================================ const getInitials = str => str.split('-').map(s => s.charAt(0)).join('') module.exports = getInitials ================================================ FILE: lib/kebab.js ================================================ const kebab = str => str.replace(/([A-Z])/g, g => '-' + g.toLowerCase()) module.exports = kebab ================================================ FILE: lib/number-to-pixel.js ================================================ const numberToPixel = val => { if (typeof val !== 'number' || val === 0) return val if (val > 0 && val <= 1) { return `${val * 100}%` } return val + 'px' } module.exports = numberToPixel ================================================ FILE: lib/styles.js ================================================ const scale = [ 0, 8, 16, 32, 64 ] const styles = [ { sel: 'h', prop: 'font-size', val: [ 48, 32, 24, 20, 16, 14, 12 ] }, { prop: [ 'margin', 'margin-top', 'margin-right', 'margin-bottom', 'margin-left', 'padding', 'padding-top', 'padding-right', 'padding-bottom', 'padding-left' ], val: scale }, { sel: 'd', prop: 'display', val: [ 'block', 'inline-block', 'inline', 'table', 'table-row', 'table-cell', 'flex', 'inline-flex' ] }, { sel: 'f', prop: 'float', val: [ 'left', 'right' ] }, { sel: 'oh', prop: 'overflow', val: 'hidden' }, { sel: 'cf:after', decs: { content: '""', display: 'block', clear: 'both' } }, { sel: 'x', prop: 'width', val: Array.from({ length: 13 }).map((n, i) => i / 12) } ] module.exports = styles ================================================ FILE: package.json ================================================ { "name": "gravitons", "version": "2.0.1", "description": "Virtually massless CSS layout microlibrary", "main": "index.js", "bin": { "gravitons": "./bin/gravitons.js" }, "style": "src/gravitons.css", "scripts": { "build": "hotdamn docs/entry.js -o docs/bundle.js", "start": "hotdamn docs/entry.js --dev", "gh-pages": "gh-pages -d docs", "test": "ava -v" }, "author": "Brent Jackson", "license": "MIT", "devDependencies": { "ava": "^0.16.0", "cssstats": "^3.0.0-beta.1", "gh-pages": "^0.11.0", "h0": "^1.0.0-beta.4", "hotdamn": "^1.1.0-beta.1" }, "dependencies": {}, "repository": { "type": "git", "url": "https://github.com/jxnblk/gravitons.git" }, "bugs": { "url": "https://github.com/jxnblk/gravitons/issues" }, "homepage": "https://github.com/jxnblk/gravitons" } ================================================ FILE: test/index.js ================================================ import test from 'ava' import gravitons from '..' let css test('returns a string', t => { css = gravitons() t.is(typeof css, 'string') }) test('includes typography rules', t => { t.regex(css, /\.h1/) t.regex(css, /\.h2/) t.regex(css, /\.h3/) t.regex(css, /\.h4/) t.regex(css, /\.h5/) t.regex(css, /\.h6/) }) test('includes margin rules', t => { t.regex(css, /\.m0/) t.regex(css, /\.m1/) t.regex(css, /\.m2/) t.regex(css, /\.m3/) t.regex(css, /\.m4/) }) test('includes padding rules', t => { t.regex(css, /\.p0/) t.regex(css, /\.p1/) t.regex(css, /\.p2/) t.regex(css, /\.p3/) t.regex(css, /\.p4/) }) test('includes display rules', t => { t.regex(css, /\.db/) t.regex(css, /\.dib/) t.regex(css, /\.di/) t.regex(css, /\.dt/) t.regex(css, /\.dtr/) t.regex(css, /\.dtc/) t.regex(css, /\.df/) t.regex(css, /\.dif/) }) test('includes float rules', t => { t.regex(css, /\.fl/) t.regex(css, /\.fr/) }) test('includes clearfix rules', t => { t.regex(css, /\.oh/) t.regex(css, /\.cf/) }) test('includes width rules', t => { t.regex(css, /\.x0/) t.regex(css, /\.x1/) t.regex(css, /\.x2/) t.regex(css, /\.x3/) t.regex(css, /\.x4/) t.regex(css, /\.x5/) t.regex(css, /\.x6/) t.regex(css, /\.x7/) t.regex(css, /\.x8/) t.regex(css, /\.x9/) t.regex(css, /\.x10/) t.regex(css, /\.x11/) t.regex(css, /\.x12/) }) test('converts numbers to pixel values', t => { t.regex(css, /:0}/) t.regex(css, /32px/) t.regex(css, /64px/) }) test('converts fractions to percentages', t => { t.regex(css, /25%}/) t.regex(css, /50%}/) t.regex(css, /100%}/) })