diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..c2c009d3e --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +# Logs +logs +*.log + +#Ignore our built files +build/* +architecture.json + +# Ignore sensitive stuff +/config/* +!/config/default.json + +node_modules \ No newline at end of file diff --git a/client/naturalCrit/monsterCard/attackSlot/attackSlot.jsx b/client/naturalCrit/monsterCard/attackSlot/attackSlot.jsx new file mode 100644 index 000000000..e68678aa5 --- /dev/null +++ b/client/naturalCrit/monsterCard/attackSlot/attackSlot.jsx @@ -0,0 +1,118 @@ +var React = require('react'); +var _ = require('lodash'); +var cx = require('classnames'); + +var AttackSlot = React.createClass({ + getDefaultProps: function() { + return { + name : '', + uses : null + }; + }, + + getInitialState: function() { + return { + lastRoll: {}, + usedCount : 0 + }; + }, + + rollDice : function(key, notation){ + var additive = 0; + var dice = _.reduce([/\+(.*)/, /\-(.*)/], function(r, regexp){ + var res = r.match(regexp); + if(res){ + additive = res[0]*1; + r = r.replace(res[0], '') + } + return r; + }, notation) + + var numDice = dice.split('d')[0]; + var die = dice.split('d')[1]; + + var diceRoll = _.times(numDice, function(){ + return _.random(1, die); + }); + var res = _.sum(diceRoll) + additive; + if(numDice == 1 && die == 20){ + if(diceRoll[0] == 1) res = 'Fail!'; + if(diceRoll[0] == 20) res = 'Crit!'; + } + this.state.lastRoll[key] = res + this.setState({ + lastRoll : this.state.lastRoll + }) + }, + + renderUses : function(){ + var self = this; + if(!this.props.uses) return null; + + return _.times(this.props.uses, function(index){ + var atCount = index < self.state.usedCount; + return + }) + }, + updateCount : function(used){ + this.setState({ + usedCount : this.state.usedCount + (used ? -1 : 1) + }); + }, + + renderNotes : function(){ + var notes = _.omit(this.props, ['name', 'atk', 'dmg', 'uses', 'heal']); + return _.map(notes, function(text, key){ + return key + ': ' + text + }).join(', '); + }, + + renderRolls : function(){ + var self = this; + + return _.map(['atk', 'dmg', 'heal'], function(type){ + if(!self.props[type]) return null; + return
+ + + {self.state.lastRoll[type] || ''} +
+ }) + + }, + + + render : function(){ + var self = this; + return( +
+
+
{this.props.name}
+
+ {this.renderUses()} +
+
+ {this.renderNotes()} +
+ +
+
+ {this.renderRolls()} +
+
+ ); + } +}); + +module.exports = AttackSlot; diff --git a/client/naturalCrit/monsterCard/attackSlot/attackSlot.less b/client/naturalCrit/monsterCard/attackSlot/attackSlot.less new file mode 100644 index 000000000..fae4b9133 --- /dev/null +++ b/client/naturalCrit/monsterCard/attackSlot/attackSlot.less @@ -0,0 +1,67 @@ + +.attackSlot{ + //border : 1px solid black; + border-bottom: 1px solid #eee; + margin-bottom : 5px; + font-size : 0.8em; + .info, .rolls{ + display : inline-block; + vertical-align : top; + } + .info{ + width : 40%; + .name{ + font-weight : 800; + } + .notes{ + font-size : 0.8em; + } + .uses{ + cursor : pointer; + } + } + .rolls{ + .roll{ + margin-bottom : 2px; + span{ + font-weight: 800; + } + button{ + width : 70px; + margin-right : 5px; + cursor : pointer; + font-size : 0.7em; + font-weight : 800; + text-align : left; + border : none; + outline : 0; + i{ + width : 15px; + margin-right : 5px; + border-right : 1px solid white; + } + &:hover{ + //text-align: right; + } + } + &.atk{ + button{ + background-color : fade(@blue, 40%); + i { border-color: @blue} + } + } + &.dmg{ + button{ + background-color : fade(@red, 40%); + i { border-color: @red} + } + } + &.heal{ + button{ + background-color : fade(@green, 40%); + i { border-color: @green} + } + } + } + } +} \ No newline at end of file diff --git a/client/naturalCrit/monsterCard/monsterCard.jsx b/client/naturalCrit/monsterCard/monsterCard.jsx new file mode 100644 index 000000000..fd9fb8706 --- /dev/null +++ b/client/naturalCrit/monsterCard/monsterCard.jsx @@ -0,0 +1,183 @@ +var React = require('react'); +var _ = require('lodash'); +var cx = require('classnames'); + +var AttackSlot = require('./attackSlot/attackSlot.jsx'); + +var MonsterCard = React.createClass({ + getDefaultProps: function() { + return { + name : '', + hp : 1, + currentHP : 1, + ac: 1, + move : 30, + attr : { + str : 8, + con : 8, + dex : 8, + int : 8, + wis : 8, + cha : 8 + }, + attacks : {}, + spells : {}, + abilities : [], + items : [], + + updateHP : function(){}, + remove : function(){}, + }; + }, + + getInitialState: function() { + return { + //currentHP: this.props.hp, + status : 'normal', + usedThings : [], + + lastRoll : { + + }, + + + mousePos : null, + tempHP : 0 + }; + }, + + componentDidMount: function() { + window.addEventListener('mousemove', this.handleMouseDrag); + window.addEventListener('mouseup', this.handleMouseUp); + }, + + handleMouseDown : function(e){ + this.setState({ + mousePos : { + x : e.pageX, + y : e.pageY, + } + }); + e.stopPropagation() + e.preventDefault() + }, + handleMouseUp : function(e){ + if(!this.state.mousePos) return; + + + this.props.updateHP(this.props.currentHP + this.state.tempHP); + this.setState({ + mousePos : null, + tempHP : 0 + }); + }, + + handleMouseDrag : function(e){ + if (!this.state.mousePos) return; + var distance = Math.sqrt(Math.pow(e.pageX - this.state.mousePos.x, 2) + Math.pow(e.pageY - this.state.mousePos.y, 2)); + var mult = (e.pageY > this.state.mousePos.y ? -1 : 1) + + this.setState({ + tempHP : Math.floor(distance * mult/25) + }) + }, + + + renderHPBox : function(){ + + var tempHP + if(this.state.tempHP){ + var sign = (this.state.tempHP > 0 ? '+' : ''); + tempHP = {['(',sign,this.state.tempHP,')'].join('')} + } + + return
+
+ {tempHP} {this.props.currentHP} +
+
{this.props.hp}
+
+ }, + + renderStats : function(){ + + }, + + + rollDice : function(key, notation){ + var additive = 0; + var dice = _.reduce([/\+(.*)/, /\-(.*)/], function(r, regexp){ + var res = r.match(regexp); + if(res){ + additive = res[0]*1; + r = r.replace(res[0], '') + } + return r; + }, notation) + + var numDice = dice.split('d')[0]; + var die = dice.split('d')[1]; + + var diceRoll = _.times(numDice, function(){ + return _.random(1, die); + }); + var res = _.sum(diceRoll) + additive; + if(numDice == 1 && die == 20){ + if(diceRoll[0] == 1) res = 'Fail!'; + if(diceRoll[0] == 20) res = 'Crit!'; + } + this.state.lastRoll[key] = res + this.setState({ + lastRoll : this.state.lastRoll + }) + }, + + + renderAttacks : function(){ + var self = this; + return _.map(this.props.attacks, function(attack, name){ + return + }) + }, + + renderSpells : function(){ + var self = this; + return _.map(this.props.spells, function(spell, name){ + return + }) + }, + + render : function(){ + var self = this; + + var condition = '' + if(this.props.currentHP + this.state.tempHP > this.props.hp) condition='overhealed'; + if(this.props.currentHP + this.state.tempHP <= this.props.hp * 0.5) condition='hurt'; + if(this.props.currentHP + this.state.tempHP <= this.props.hp * 0.2) condition='last_legs'; + if(this.props.currentHP + this.state.tempHP <= 0) condition='dead'; + + + return( +
+
+
+ + + {this.renderHPBox()} +
{this.props.name}
+ +
+ {this.renderAttacks()} +
+
+ {this.renderSpells()} +
+ {this.props.initiative} + + +
+ ); + } +}); + +module.exports = MonsterCard; diff --git a/client/naturalCrit/monsterCard/monsterCard.less b/client/naturalCrit/monsterCard/monsterCard.less new file mode 100644 index 000000000..f3850b8ad --- /dev/null +++ b/client/naturalCrit/monsterCard/monsterCard.less @@ -0,0 +1,77 @@ + +.noselect(){ + -webkit-touch-callout : none; + -webkit-user-select : none; + -khtml-user-select : none; + -moz-user-select : none; + -ms-user-select : none; + user-select : none; +} +.monsterCard{ + position : relative; + display : inline-block; + vertical-align : top; + box-sizing : border-box; + width : 250px; + margin : 30px; + padding : 10px; + background-color : white; + border : 1px solid #bbb; + .healthbar{ + position : absolute; + top : 0px; + left : 0px; + height : 3px; + max-width : 100%; + background-color : @green; + z-index : 50; + } + .overhealbar{ + position : absolute; + top : 0px; + left : 0px; + height : 3px; + max-width : 100%; + background-color : @blueLight; + z-index : 100; + } + &.hurt{ + .healthbar{ + background-color : orange; + } + } + &.last_legs{ + background-color: lighten(@red, 49%); + .healthbar{ + background-color : red; + } + } + &.dead{ + opacity: 0.3; + } + .hpBox{ + .noselect(); + position : absolute; + top : 5px; + right : 5px; + cursor : pointer; + text-align : right; + .currentHP{ + font-size : 2em; + font-weight : 800; + line-height : 0.8em; + .tempHP{ + vertical-align : top; + font-size : 0.4em; + line-height : 0.8em; + } + } + .maxHP{ + font-size : 0.8em; + } + .hpText{ + font-size : 0.6em; + font-weight : 800; + } + } +} \ No newline at end of file diff --git a/client/naturalCrit/naturalCrit.jsx b/client/naturalCrit/naturalCrit.jsx new file mode 100644 index 000000000..dc4c66c84 --- /dev/null +++ b/client/naturalCrit/naturalCrit.jsx @@ -0,0 +1,155 @@ +var React = require('react'); +var _ = require('lodash'); +var cx = require('classnames'); + +var MonsterCard = require('./monsterCard/monsterCard.jsx'); + + +var encounter = { + + name : 'The Big Bad', + enemies : ['goblin', 'goblin'], + reserve : ['goblin'], + +} + +var MonsterManual = { + 'goblin' : { + "hp" : 40, + "mov": 30, + "attr" : { + "str" : 8, + "con" : 8, + "dex" : 8, + "int" : 8, + "wis" : 8, + "cha" : 8 + }, + "attacks" : { + "dagger" : { + "atk" : "1d20-5", + "dmg" : "1d4+5", + "type" : "pierce", + "notes" : "Super cool" + }, + "bow" : { + "atk" : "1d20+2", + "dmg" : "6d6", + "rng" : "30" + } + }, + "spells" : { + "fireball": { + "dmg" : "6d6", + "uses" : 4 + }, + "healing_bolt" : { + "heal" : "2d8+4", + "uses" : 6 + } + }, + "abilities" : ["pack tactics"], + "items" : [] + } +} + +var attrMod = function(attr){ + return Math.floor(attr/2) - 5; +} + + +var NaturalCrit = React.createClass({ + + getInitialState: function() { + var self = this; + + return { + enemies: _.indexBy(_.map(encounter.enemies, function(type, index){ + return self.createEnemy(type, index) + }), 'id') + }; + }, + + createEnemy : function(type, index){ + var stats = MonsterManual[type] + return _.extend({ + id : type + index, + name : type, + currentHP : stats.hp, + initiative : _.random(1,20) + attrMod(stats.attr.dex) + }, stats); + }, + + addPC : function(name, initiative){ + this.state.enemies[name] = { + name : name, + id : name, + initiative : initiative, + isPC : true + }; + this.setState({ + enemies : this.state.enemies + }) + + }, + + + addRandomPC : function(){ + this.addPC( + _.sample(['zatch', 'jasper', 'el toro', 'tulik']) + _.random(1,1000), + _.random(1,25) + ) + }, + + + updateHP : function(enemyId, newHP){ + this.state.enemies[enemyId].currentHP = newHP; + this.setState({ + enemies : this.state.enemies + }); + }, + removeEnemy : function(enemyId){ + delete this.state.enemies[enemyId]; + this.setState({ + enemies : this.state.enemies + }); + }, + + + + + + render : function(){ + var self = this; + + console.log(); + + var sortedEnemies = _.sortBy(this.state.enemies, function(e){ + return -e.initiative; + }); + + + var cards = _.map(sortedEnemies, function(enemy){ + return + }) + + + + return( +
+ + Project Ready! + + {cards} +
+ ); + } +}); + +module.exports = NaturalCrit; + + diff --git a/client/naturalCrit/naturalCrit.less b/client/naturalCrit/naturalCrit.less new file mode 100644 index 000000000..40a6b2fd4 --- /dev/null +++ b/client/naturalCrit/naturalCrit.less @@ -0,0 +1,19 @@ +@import 'naturalCrit/reset.less'; +//@import 'naturalCrit/elements.less'; +@import 'naturalCrit/animations.less'; +@import 'naturalCrit/colors.less'; + +body{ + background-color : #eee; + font-family : 'Open Sans', sans-serif; + color : #4b5055; + font-weight : 100; + text-rendering : optimizeLegibility; + margin : 0; + padding : 0; +} + +.naturalCrit{ + color : #333; + background-color: #eee; +} \ No newline at end of file diff --git a/client/template.dot b/client/template.dot new file mode 100644 index 000000000..708c46e7c --- /dev/null +++ b/client/template.dot @@ -0,0 +1,18 @@ + + + + + + + + {{=vitreum.css}} + {{=vitreum.globals}} + NaturalCrit + + +
{{=vitreum.component}}
+ + {{=vitreum.libs}} + {{=vitreum.js}} + {{=vitreum.reactRender}} + diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 000000000..1e5864d4c --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,30 @@ +"use strict"; + +var vitreumTasks = require("vitreum/tasks"); +var gulp = require("gulp"); + + +var gulp = vitreumTasks(gulp, { + entryPoints: ["./client/naturalCrit"], + DEV: true, + + buildPath: "./build/", + pageTemplate: "./client/template.dot", + + projectModules: ["./shared/naturalCrit"], + additionalRequirePaths : ['./shared'], + assetExts: ["*.svg", "*.png", "*.jpg", "*.pdf", "*.eot", "*.ttf", "*.woff", "*.woff2", "*.ico"], + + serverWatchPaths: ["server"], + serverScript: "server.js", + libs: [ + "react", + "react-dom", + "lodash", + "classnames", + + ], + clientLibs: [], +}); + + diff --git a/package.json b/package.json new file mode 100644 index 000000000..181abd469 --- /dev/null +++ b/package.json @@ -0,0 +1,21 @@ +{ + "name": "naturalCrit", + "description": "A super rad project!", + "version": "0.0.0", + "scripts": { + "postinstall": "gulp prod", + "start": "node server.js" + }, + "author": "", + "license": "BSD-2-Clause", + "dependencies": { + "app-module-path": "^1.0.4", + "classnames": "^2.2.0", + "express": "^4.13.3", + "gulp": "^3.9.0", + "lodash": "^3.10.1", + "react": "^0.14.2", + "react-dom": "^0.14.2", + "vitreum": "^3.1.1" + } +} diff --git a/server.js b/server.js new file mode 100644 index 000000000..29179ba8d --- /dev/null +++ b/server.js @@ -0,0 +1,30 @@ +'use strict'; +require('app-module-path').addPath('./shared'); +var vitreumRender = require('vitreum/render'); +var express = require("express"); +var app = express(); +app.use(express.static(__dirname + '/build')); + + + + +app.get('*', function (req, res) { + vitreumRender({ + page: './build/naturalCrit/bundle.dot', + globals:{ + + }, + //prerenderWith : './client/naturalCrit/naturalCrit.jsx', + initialProps: { + url: req.originalUrl + }, + clearRequireCache : true, + }, function (err, page) { + return res.send(page) + }); +}); + + +var port = process.env.PORT || 8000; +app.listen(port); +console.log('Listening on localhost:' + port); \ No newline at end of file diff --git a/server/Server files go here b/server/Server files go here new file mode 100644 index 000000000..e69de29bb diff --git a/shared/naturalCrit/animations.less b/shared/naturalCrit/animations.less new file mode 100644 index 000000000..7857f559e --- /dev/null +++ b/shared/naturalCrit/animations.less @@ -0,0 +1,421 @@ +//Defaults +@defaultDuration : 0.25s; +@defaultEasing : ease; + +//Animates all properties on an element +.animateAll(@duration : @defaultDuration, @easing : @defaultEasing){ + -webkit-transition: all @duration @easing; + -moz-transition: all @duration @easing; + -o-transition: all @duration @easing; + transition: all @duration @easing; +} +//Animates Specific property +.animate(@prop, @duration : @defaultDuration, @easing : @defaultEasing){ + -webkit-transition: @prop @duration @easing; + -moz-transition: @prop @duration @easing; + -o-transition: @prop @duration @easing; + transition: @prop @duration @easing; +} + +.animateMany(...){ + @value: ~`"@{arguments}".replace(/[\[\]]|\,\sX/g, '')`; + -webkit-transition-property: @value; + -moz-transition-property: @value; + -o-transition-property: @value; + transition-property: @value; + + .animateDuration(); + .animateEasing(); +} + +.animateDuration(@duration : @defaultDuration){ + -webkit-transition-duration: @duration; + -moz-transition-duration: @duration; + -o-transition-duration: @duration; + transition-duration: @duration; +} + +.animateEasing(@easing : @defaultEasing){ + -webkit-transition-timing-function: @easing; + -moz-transition-timing-function: @easing; + -o-transition-timing-function: @easing; + transition-timing-function: @easing; +} + + +.transition (@prop, @duration: @defaultDuration) { + -webkit-transition: @prop @duration, -webkit-transform @duration; + -moz-transition: @prop @duration, -moz-transform @duration; + -o-transition: @prop @duration, -o-transform @duration; + -ms-transition: @prop @duration, -ms-transform @duration; + transition: @prop @duration, transform @duration; +} +.transform (@transform) { + -webkit-transform: @transform; + -moz-transform: @transform; + -o-transform: @transform; + -ms-transform: @transform; + transform: @transform; +} + + +.delay(@delay){ + animation-delay:@delay; + -webkit-animation-delay:@delay; + transition-delay:@delay; + -webkit-transition-delay:@delay; +} +.keep(){ + -webkit-animation-fill-mode:forwards; + -moz-animation-fill-mode:forwards; + -ms-animation-fill-mode:forwards; + -o-animation-fill-mode:forwards; + animation-fill-mode:forwards; +} + + +.sequentialDelay(@delayInc : 0.2s, @initialDelay : 0s){ + &:nth-child(1){.delay(0*@delayInc + @initialDelay)} + &:nth-child(2){.delay(1*@delayInc + @initialDelay)} + &:nth-child(3){.delay(2*@delayInc + @initialDelay)} + &:nth-child(4){.delay(3*@delayInc + @initialDelay)} + &:nth-child(5){.delay(4*@delayInc + @initialDelay)} + &:nth-child(6){.delay(5*@delayInc + @initialDelay)} + &:nth-child(7){.delay(6*@delayInc + @initialDelay)} + &:nth-child(8){.delay(7*@delayInc + @initialDelay)} + &:nth-child(9){.delay(8*@delayInc + @initialDelay)} + &:nth-child(10){.delay(9*@delayInc + @initialDelay)} + &:nth-child(11){.delay(10*@delayInc + @initialDelay)} + &:nth-child(12){.delay(11*@delayInc + @initialDelay)} + &:nth-child(13){.delay(12*@delayInc + @initialDelay)} + &:nth-child(14){.delay(13*@delayInc + @initialDelay)} + &:nth-child(15){.delay(14*@delayInc + @initialDelay)} + &:nth-child(16){.delay(15*@delayInc + @initialDelay)} + &:nth-child(17){.delay(16*@delayInc + @initialDelay)} + &:nth-child(18){.delay(17*@delayInc + @initialDelay)} + &:nth-child(19){.delay(18*@delayInc + @initialDelay)} + &:nth-child(20){.delay(19*@delayInc + @initialDelay)} +} + + + +.createFrames(@name, @from, @to){ + @frames: { + from { @from(); } + to { @to(); } + }; + @-webkit-keyframes @name {@frames();} + @-moz-keyframes @name {@frames();} + @-ms-keyframes @name {@frames();} + @-o-keyframes @name {@frames();} + @keyframes @name {@frames();} +} + +.createAnimation(@name, @duration : @defaultDuration, @easing : @defaultEasing){ + -webkit-animation-name: @name; + -moz-animation-name: @name; + -ms-animation-name: @name; + animation-name: @name; + -webkit-animation-duration: @duration; + -moz-animation-duration: @duration; + -ms-animation-duration: @duration; + animation-duration: @duration; + -webkit-animation-timing-function: @easing; + -moz-animation-timing-function: @easing; + -ms-animation-timing-function: @easing; + animation-timing-function: @easing; +} + + + +/*************************** + Standard Animations +****************************/ + +.fadeIn(@duration : @defaultDuration, @easing : @defaultEasing){ + .createAnimation(fadeIn; @duration; @easing); + .createFrames(fadeIn, + { opacity : 0; }, + { opacity : 1; } + ); +} + +.fadeInDown(@duration : @defaultDuration, @easing : @defaultEasing){ + .createAnimation(fadeInDown; @duration; @easing); + .createFrames(fadeInDown, + { opacity : 0; .transform(translateY(20px));}, + { opacity : 1; .transform(translateY(0px));} + ); +} + +.fadeInTop(@duration : @defaultDuration, @easing : @defaultEasing){ + .createAnimation(fadeInTop; @duration; @easing); + .createFrames(fadeInTop, + { opacity : 0; .transform(translateY(-20px)); }, + { opacity : 1; .transform(translateY(0px));} + ); +} + +.fadeInLeft(@duration : @defaultDuration, @easing : @defaultEasing){ + .createAnimation(fadeInLeft; @duration; @easing); + .createFrames(fadeInLeft, + { opacity: 0; .transform(translateX(-20px));}, + { opacity: 1; .transform(translateX(0));} + ); +} + +.fadeInRight(@duration : @defaultDuration, @easing : @defaultEasing){ + .createAnimation(fadeInRight; @duration; @easing); + .createFrames(fadeInRight, + { opacity: 0; .transform(translateX(20px));}, + { opacity: 1; .transform(translateX(0));} + ); +} + +.fadeOut(@duration : @defaultDuration, @easing : @defaultEasing){ + .createAnimation(fadeOut; @duration; @easing); + .createFrames(fadeOut, + { opacity : 1; }, + { opacity : 0; } + ); +} + +.fadeOutDown(@duration : @defaultDuration, @easing : @defaultEasing){ + .createAnimation(fadeOutDown; @duration; @easing); + .createFrames(fadeOutDown, + { opacity : 1; .transform(translateY(0)); visibility: visible;}, + { opacity : 0; .transform(translateY(20px)); visibility: hidden;} + ); +} + +.fadeOutTop(@duration : @defaultDuration, @easing : @defaultEasing){ + .createAnimation(fadeOutTop; @duration; @easing); + .createFrames(fadeOutTop, + { opacity : 1; .transform(translateY(0)); }, + { opacity : 0; .transform(translateY(-20px)); } + ); +} + +.fadeOutLeft(@duration : @defaultDuration, @easing : @defaultEasing){ + .createAnimation(fadeOutLeft; @duration; @easing); + .createFrames(fadeOutLeft, + { opacity : 1; .transform(translateX(0));}, + { opacity : 0; .transform(translateX(-20px));} + ); +} + +.fadeOutRight(@duration : @defaultDuration, @easing : @defaultEasing){ + .createAnimation(fadeOutRight; @duration; @easing); + .createFrames(fadeOutRight, + { opacity : 1; .transform(translateX(0));}, + { opacity : 0; .transform(translateX(20px));} + ); +} + + + + +/*************************** + Fun Animations +****************************/ + +.spin(@duration : @defaultDuration, @easing : @defaultEasing){ + .createAnimation(spin, @duration, @easing); + .spinKeyFrames(){ + from { .transform(rotate(0deg)); } + to { .transform(rotate(360deg)); } + } + @-webkit-keyframes spin {.spinKeyFrames();} + @-moz-keyframes spin {.spinKeyFrames();} + @-ms-keyframes spin {.spinKeyFrames();} + @-o-keyframes spin {.spinKeyFrames();} + @keyframes spin {.spinKeyFrames();} +} + +.bounce(@duration : @defaultDuration, @easing : @defaultEasing){ + .createAnimation(bounce, @duration, @easing); + .bounceKeyFrames(){ + 0%, 20%, 50%, 80%, 100% { .transform(translateY(0));} + 40% { .transform(translateY(-30px));} + 60% { .transform(translateY(-15px));} + } + @-webkit-keyframes bounce {.bounceKeyFrames();} + @-moz-keyframes bounce {.bounceKeyFrames();} + @-ms-keyframes bounce {.bounceKeyFrames();} + @-o-keyframes bounce {.bounceKeyFrames();} + @keyframes bounce {.bounceKeyFrames();} +} + +.pulse(@duration : @defaultDuration, @easing : @defaultEasing){ + .createAnimation(pulse, @duration, @easing); + .pulseKeyFrames(){ + 0% { .transform(scale(1));} + 50% { .transform(scale(1.4));} + 100% { .transform(scale(1));} + } + @-webkit-keyframes pulse {.pulseKeyFrames();} + @-moz-keyframes pulse {.pulseKeyFrames();} + @-ms-keyframes pulse {.pulseKeyFrames();} + @-o-keyframes pulse {.pulseKeyFrames();} + @keyframes pulse {.pulseKeyFrames();} +} + +.rubberBand(@duration : @defaultDuration, @easing : @defaultEasing){ + .createAnimation(rubberBand, @duration, @easing); + .rubberBandKeyFrames(){ + 0% {.transform(scale(1));} + 30% {.transform(scaleX(1.25) scaleY(0.75));} + 40% {.transform(scaleX(0.75) scaleY(1.25));} + 60% {.transform(scaleX(1.15) scaleY(0.85));} + 100% {.transform(scale(1));} + } + @-webkit-keyframes rubberBand {.rubberBandKeyFrames();} + @-moz-keyframes rubberBand {.rubberBandKeyFrames();} + @-ms-keyframes rubberBand {.rubberBandKeyFrames();} + @-o-keyframes rubberBand {.rubberBandKeyFrames();} + @keyframes rubberBand {.rubberBandKeyFrames();} +} + +.shake(@duration : @defaultDuration, @easing : @defaultEasing){ + .createAnimation(shake, @duration, @easing); + .shakeKeyFrames(){ + 0%, 100% {.transform( translateX(0));} + 10%, 30%, 50%, 70%, 90% {.transform( translateX(-10px));} + 20%, 40%, 60%, 80% {.transform( translateX(10px));} + } + @-webkit-keyframes shake {.shakeKeyFrames();} + @-moz-keyframes shake {.shakeKeyFrames();} + @-ms-keyframes shake {.shakeKeyFrames();} + @-o-keyframes shake {.shakeKeyFrames();} + @keyframes shake {.shakeKeyFrames();} +} + +.swing(@duration : @defaultDuration, @easing : @defaultEasing){ + -webkit-transform-origin: top center; + -ms-transform-origin: top center; + transform-origin: top center; + .createAnimation(swing, @duration, @easing); + .swingKeyFrames(){ + 20% {.transform(rotate(15deg));} + 40% {.transform(rotate(-10deg));} + 60% {.transform(rotate(5deg));} + 80% {.transform(rotate(-5deg));} + 100% {.transform(rotate(0deg));} + } + @-webkit-keyframes swing {.swingKeyFrames();} + @-moz-keyframes swing {.swingKeyFrames();} + @-ms-keyframes swing {.swingKeyFrames();} + @-o-keyframes swing {.swingKeyFrames();} + @keyframes swing {.swingKeyFrames();} +} + +.twist(@duration : @defaultDuration, @easing : @defaultEasing){ + -webkit-transform-origin: center center; + -ms-transform-origin: center center; + transform-origin: center center; + .createAnimation(swing, @duration, @easing); + .swingKeyFrames(){ + 20% {.transform(rotate(15deg));} + 40% {.transform(rotate(-10deg));} + 60% {.transform(rotate(5deg));} + 80% {.transform(rotate(-5deg));} + 100% {.transform(rotate(0deg));} + } + @-webkit-keyframes swing {.swingKeyFrames();} + @-moz-keyframes swing {.swingKeyFrames();} + @-ms-keyframes swing {.swingKeyFrames();} + @-o-keyframes swing {.swingKeyFrames();} + @keyframes swing {.swingKeyFrames();} +} + +.wobble(@duration : @defaultDuration, @easing : @defaultEasing){ + .createAnimation(wobble, @duration, @easing); + .wobbleKeyFrames(){ + 0% {.transform(translateX(0%));} + 15% {.transform(translateX(-25%) rotate(-5deg));} + 30% {.transform(translateX(20%) rotate(3deg));} + 45% {.transform(translateX(-15%) rotate(-3deg));} + 60% {.transform(translateX(10%) rotate(2deg));} + 75% {.transform(translateX(-5%) rotate(-1deg));} + 100% {.transform(translateX(0%));} + } + @-webkit-keyframes wobble {.wobbleKeyFrames();} + @-moz-keyframes wobble {.wobbleKeyFrames();} + @-ms-keyframes wobble {.wobbleKeyFrames();} + @-o-keyframes wobble {.wobbleKeyFrames();} + @keyframes wobble {.wobbleKeyFrames();} +} + +.popIn(@duration : @defaultDuration, @easing : @defaultEasing){ + .createAnimation(popIn, @duration, @easing); + .popInKeyFrames(){ + 0% { .transform(scale(0));} + 70% { .transform(scale(1.4));} + 100% { .transform(scale(1));} + } + @-webkit-keyframes popIn {.popInKeyFrames();} + @-moz-keyframes popIn {.popInKeyFrames();} + @-ms-keyframes popIn {.popInKeyFrames();} + @-o-keyframes popIn {.popInKeyFrames();} + @keyframes popIn {.popInKeyFrames();} +} + +.rumble(@duration : @defaultDuration, @easing : @defaultEasing){ + .createAnimation(rumble, @duration, @easing); + .rumbleKeyFrames(){ + 2% { .transform(translate(-0.5px, 1.5px) rotate(0.5deg)); } + 4% { .transform(translate(-0.5px, 1.5px) rotate(-0.5deg)); } + 6% { .transform(translate(-2.5px, -1.5px) rotate(0.5deg)); } + 8% { .transform(translate(-2.5px, -2.5px) rotate(-1.5deg)); } + 10% { .transform(translate(1.5px, 1.5px) rotate(-1.5deg)); } + 12% { .transform(translate(-2.5px, -0.5px) rotate(-0.5deg)); } + 14% { .transform(translate(1.5px, -2.5px) rotate(-0.5deg)); } + 16% { .transform(translate(0.5px, 1.5px) rotate(0.5deg)); } + 18% { .transform(translate(-2.5px, -0.5px) rotate(0.5deg)); } + 20% { .transform(translate(-0.5px, -0.5px) rotate(-1.5deg)); } + 22% { .transform(translate(-2.5px, -1.5px) rotate(-1.5deg)); } + 24% { .transform(translate(-1.5px, -2.5px) rotate(-1.5deg)); } + 26% { .transform(translate(0.5px, -0.5px) rotate(-1.5deg)); } + 28% { .transform(translate(-0.5px, -1.5px) rotate(-0.5deg)); } + 30% { .transform(translate(-2.5px, 1.5px) rotate(0.5deg)); } + 32% { .transform(translate(-2.5px, -2.5px) rotate(-0.5deg)); } + 34% { .transform(translate(-1.5px, 0.5px) rotate(-1.5deg)); } + 36% { .transform(translate(1.5px, -1.5px) rotate(-1.5deg)); } + 38% { .transform(translate(0.5px, -0.5px) rotate(-0.5deg)); } + 40% { .transform(translate(-0.5px, 0.5px) rotate(0.5deg)); } + 42% { .transform(translate(0.5px, -2.5px) rotate(-0.5deg)); } + 44% { .transform(translate(0.5px, -2.5px) rotate(-0.5deg)); } + 46% { .transform(translate(-1.5px, 1.5px) rotate(-1.5deg)); } + 48% { .transform(translate(0.5px, -2.5px) rotate(-0.5deg)); } + 50% { .transform(translate(-1.5px, -0.5px) rotate(-1.5deg)); } + 52% { .transform(translate(-2.5px, -0.5px) rotate(-1.5deg)); } + 54% { .transform(translate(1.5px, 0.5px) rotate(-1.5deg)); } + 56% { .transform(translate(0.5px, 0.5px) rotate(-1.5deg)); } + 58% { .transform(translate(0.5px, 1.5px) rotate(-0.5deg)); } + 60% { .transform(translate(-0.5px, -2.5px) rotate(-0.5deg)); } + 62% { .transform(translate(-2.5px, -1.5px) rotate(-0.5deg)); } + 64% { .transform(translate(-1.5px, 0.5px) rotate(0.5deg)); } + 66% { .transform(translate(0.5px, -0.5px) rotate(-1.5deg)); } + 68% { .transform(translate(-1.5px, -0.5px) rotate(-1.5deg)); } + 70% { .transform(translate(-0.5px, -2.5px) rotate(-1.5deg)); } + 72% { .transform(translate(-2.5px, -0.5px) rotate(-1.5deg)); } + 74% { .transform(translate(-2.5px, 0.5px) rotate(0.5deg)); } + 76% { .transform(translate(1.5px, -1.5px) rotate(-1.5deg)); } + 78% { .transform(translate(1.5px, -2.5px) rotate(0.5deg)); } + 80% { .transform(translate(-2.5px, -2.5px) rotate(-0.5deg)); } + 82% { .transform(translate(-2.5px, -1.5px) rotate(0.5deg)); } + 84% { .transform(translate(0.5px, -2.5px) rotate(-0.5deg)); } + 86% { .transform(translate(-2.5px, 0.5px) rotate(-0.5deg)); } + 88% { .transform(translate(-2.5px, -0.5px) rotate(-0.5deg)); } + 90% { .transform(translate(-1.5px, -1.5px) rotate(-1.5deg)); } + 92% { .transform(translate(-0.5px, -1.5px) rotate(-0.5deg)); } + 94% { .transform(translate(0.5px, -0.5px) rotate(-0.5deg)); } + 96% { .transform(translate(-2.5px, -2.5px) rotate(0.5deg)); } + 98% { .transform(translate(-0.5px, 1.5px) rotate(-0.5deg)); } + } + @-webkit-keyframes rumble {.rumbleKeyFrames();} + @-moz-keyframes rumble {.rumbleKeyFrames();} + @-ms-keyframes rumble {.rumbleKeyFrames();} + @-o-keyframes rumble {.rumbleKeyFrames();} + @keyframes rumble {.rumbleKeyFrames();} +} \ No newline at end of file diff --git a/shared/naturalCrit/colors.less b/shared/naturalCrit/colors.less new file mode 100644 index 000000000..67768d811 --- /dev/null +++ b/shared/naturalCrit/colors.less @@ -0,0 +1,23 @@ + +@copyGrey : #333333; + +@tealLight : #1ABC9C; +@teal : #16A085; +@greenLight : #2ECC71; +@green : #27AE60; +@blueLight : #3498DB; +@blue : #2980B9; +@purpleLight : #9B59B6; +@purple : #8E44AD; +@steelLight : #34495E; +@steel : #2C3E50; +@yellowLight : #F1C40F; +@yellow : #F39C12; +@orangeLight : #E67E22; +@orange : #D35400; +@redLight : #E74C3C; +@red : #C0392B; +@silverLight : #ECF0F1; +@silver : #BDC3C7; +@greyLight : #95A5A6; +@grey : #7F8C8D; \ No newline at end of file diff --git a/shared/naturalCrit/elements.less b/shared/naturalCrit/elements.less new file mode 100644 index 000000000..6dff02aa7 --- /dev/null +++ b/shared/naturalCrit/elements.less @@ -0,0 +1,86 @@ + +@containerWidth : 1000px; + +html, body{ + position : relative; + height : 100%; + min-height : 100%; + background-color : #eee; + font-family : 'Lato', sans-serif; + color : @copyGrey; +} +.container{ + position : relative; + max-width : @containerWidth; + margin : 0 auto; + padding-right : 20px; + padding-left : 20px; +} +h1{ + margin-top : 10px; + margin-bottom : 15px; + font-size : 2em; +} +h2{ + margin-top : 10px; + margin-bottom : 15px; + font-size : 1.5em; + font-weight : 900; +} +h3{ + margin-top : 5px; + margin-bottom : 7px; + font-size : 1em; + font-weight : 900; +} +p{ + margin-bottom : 1em; + font-size : 16px; + color : @copyGrey; + line-height : 1.5em; +} +code{ + background-color : #F8F8F8; + font-family : 'Courier', mono; + color : black; + white-space : pre; +} +a{ + color : inherit; +} +strong{ + font-weight : bold; +} +button{ + .button(); +} +.button(@backgroundColor : @green){ + .animate(background-color); + display : inline-block; + padding : 0.6em 1.2em; + cursor : pointer; + background-color : @backgroundColor; + font-family : "Lato", Helvetica, Arial, sans-serif; + font-size : 15px; + color : white; + text-decoration : none; + border : none; + outline : none; + &:hover{ + background-color : darken(@backgroundColor, 5%); + } + &:active{ + background-color : darken(@backgroundColor, 10%); + } + &:disabled{ + background-color : @silver !important; + } +} +.iconButton(@backgroundColor : @green){ + padding : 0.6em; + cursor : pointer; + background-color : @backgroundColor; + font-size : 14px; + color : white; + text-align : center; +} \ No newline at end of file diff --git a/shared/naturalCrit/reset.less b/shared/naturalCrit/reset.less new file mode 100644 index 000000000..b0854aa33 --- /dev/null +++ b/shared/naturalCrit/reset.less @@ -0,0 +1,2 @@ +/* Eric Meyer's Reset CSS v2.0 - http://cssreset.com */ +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{border:0;font-size:100%;font:inherit;vertical-align:baseline;margin:0;padding:0}article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{display:block}body{line-height:1}ol,ul{list-style:none}blockquote,q{quotes:none}blockquote:before,blockquote:after,q:before,q:after{content:none}table{border-collapse:collapse;border-spacing:0} \ No newline at end of file