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
[](https://travis-ci.org/jxnblk/gravitons)
```sh
npm i -g gravitons
```

```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%}/)
})