├── app ├── utils │ ├── .gitkeep │ └── ajax.js ├── views │ └── .gitkeep ├── components │ ├── .gitkeep │ ├── pretty-color.js │ └── markdown-textfield.js ├── helpers │ ├── .gitkeep │ ├── markdown-text.js │ └── reverse-word.js ├── models │ ├── .gitkeep │ ├── channel.js │ └── message.js ├── routes │ ├── .gitkeep │ ├── component_test.js │ ├── helper_test.js │ └── index.js ├── styles │ ├── .gitkeep │ ├── app.scss │ └── _settings.scss ├── templates │ ├── .gitkeep │ ├── components │ │ ├── .gitkeep │ │ ├── markdown-textfield.hbs │ │ └── pretty-color.hbs │ ├── helper-test.hbs │ ├── component-test.hbs │ ├── index.hbs │ ├── application.hbs │ └── message.hbs ├── controllers │ ├── .gitkeep │ ├── user.js │ ├── application.js │ ├── message.js │ ├── event_bus.js │ └── index.js ├── adapters │ └── application.js ├── serializers │ └── channel.js ├── router.js ├── app.js └── index.html ├── public ├── assets │ └── .gitkeep ├── robots.txt ├── humans.txt └── crossdomain.xml ├── tests ├── unit │ ├── .gitkeep │ └── routes │ │ └── index_test.js ├── test_loader.js ├── acceptance │ ├── helper_test.js │ ├── index_test.js │ └── component_test.js ├── helpers │ ├── start_app.js │ └── isolated_container.js ├── test_helper.js └── .jshintrc ├── .bowerrc ├── .rvmrc ├── Gemfile ├── tasks ├── options │ ├── usemin.js │ ├── clean.js │ ├── useminPrepare.js │ ├── concurrent.js │ ├── imagemin.js │ ├── less.js │ ├── stylus.js │ ├── express-server.js │ ├── htmlmin.js │ ├── sass.js │ ├── rev.js │ ├── emblem.js │ ├── jshint.js │ ├── compass.js │ ├── concat_sourcemap.js │ ├── preprocess.js │ ├── fancySprites.js │ ├── transpile.js │ ├── emberTemplates.js │ ├── emberscript.js │ ├── coffee.js │ ├── watch.js │ ├── copy.js │ └── testem.js ├── locking.js ├── .jshintrc ├── helpers.js └── express-server.js ├── .travis.yml ├── config ├── environments │ ├── test.js │ ├── production.js │ └── development.js └── environment.js ├── Gemfile.lock ├── .gitignore ├── README.md ├── bower.json ├── .jshintrc ├── api-stub ├── routes.js └── README.md ├── LICENSE ├── vendor └── loader.js ├── package.json └── Gruntfile.js /app/utils/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/views/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/components/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/helpers/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/models/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/routes/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/styles/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/templates/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/unit/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/controllers/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/templates/components/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "vendor" 3 | } 4 | -------------------------------------------------------------------------------- /app/templates/components/markdown-textfield.hbs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.rvmrc: -------------------------------------------------------------------------------- 1 | rvm use --create ruby-1.9.3-p392@lagerfeuer-ember 2 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # robotstxt.org/ 2 | 3 | User-agent: * 4 | -------------------------------------------------------------------------------- /app/templates/components/pretty-color.hbs: -------------------------------------------------------------------------------- 1 | Pretty Color: {{name}} 2 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'compass', '~> 0.12.2' 4 | -------------------------------------------------------------------------------- /app/controllers/user.js: -------------------------------------------------------------------------------- 1 | export default Ember.ObjectController.extend({}); 2 | -------------------------------------------------------------------------------- /app/templates/helper-test.hbs: -------------------------------------------------------------------------------- 1 |

My name is {{reverse-word name}}.

2 | -------------------------------------------------------------------------------- /tasks/options/usemin.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | html: ['dist/index.html'], 3 | }; 4 | -------------------------------------------------------------------------------- /app/templates/component-test.hbs: -------------------------------------------------------------------------------- 1 | {{#each}} 2 | {{pretty-color name=this}} 3 | {{/each}} 4 | -------------------------------------------------------------------------------- /tasks/options/clean.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'debug': ['tmp'], 3 | 'dist': ['tmp', 'dist'] 4 | }; 5 | -------------------------------------------------------------------------------- /app/adapters/application.js: -------------------------------------------------------------------------------- 1 | export default DS.ActiveModelAdapter.extend({ 2 | host: 'http://localhost:8080' 3 | }); 4 | -------------------------------------------------------------------------------- /app/utils/ajax.js: -------------------------------------------------------------------------------- 1 | /* global ic */ 2 | export default function ajax(){ 3 | return ic.ajax.apply(null, arguments); 4 | } 5 | -------------------------------------------------------------------------------- /tasks/options/useminPrepare.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | html: 'tmp/result/index.html', 3 | options: { 4 | dest: 'dist/' 5 | } 6 | }; 7 | -------------------------------------------------------------------------------- /app/routes/component_test.js: -------------------------------------------------------------------------------- 1 | export default Ember.Route.extend({ 2 | model: function() { 3 | return ['purple', 'green', 'orange']; 4 | } 5 | }); 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 0.10 4 | before_script: 5 | - npm install -g grunt-cli 6 | - npm install -g bower 7 | - bower install 8 | -------------------------------------------------------------------------------- /app/routes/helper_test.js: -------------------------------------------------------------------------------- 1 | export default Ember.Route.extend({ 2 | model: function() { 3 | return { 4 | name: "rebmE" 5 | }; 6 | } 7 | }); 8 | -------------------------------------------------------------------------------- /app/models/channel.js: -------------------------------------------------------------------------------- 1 | var Channel = DS.Model.extend({ 2 | title: DS.attr(), 3 | messages: DS.hasMany('message', { async: true }) 4 | }); 5 | 6 | export default Channel; 7 | -------------------------------------------------------------------------------- /app/serializers/channel.js: -------------------------------------------------------------------------------- 1 | export default DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { 2 | attrs: { 3 | messages: { embedded: 'always' } 4 | } 5 | }); 6 | -------------------------------------------------------------------------------- /tasks/options/concurrent.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // Remaining configuration done in Gruntfile.js 3 | options: { 4 | logConcurrentOutput: true 5 | } 6 | }; 7 | -------------------------------------------------------------------------------- /app/controllers/application.js: -------------------------------------------------------------------------------- 1 | export default Ember.Controller.extend({ 2 | needs: ['eventBus'], 3 | 4 | init: function() { 5 | this.get('controllers.eventBus').connectEventBus(); 6 | } 7 | }); 8 | -------------------------------------------------------------------------------- /config/environments/test.js: -------------------------------------------------------------------------------- 1 | // Put your test configuration here. 2 | // 3 | // This is useful when using a separate API 4 | // endpoint in test than in production. 5 | // 6 | // window.ENV.public_key = '123456' 7 | -------------------------------------------------------------------------------- /config/environments/production.js: -------------------------------------------------------------------------------- 1 | // Put your production configuration here. 2 | // 3 | // This is useful when using a separate API 4 | // endpoint in development than in production. 5 | // 6 | // window.ENV.public_key = '123456' 7 | -------------------------------------------------------------------------------- /config/environments/development.js: -------------------------------------------------------------------------------- 1 | // Put your development configuration here. 2 | // 3 | // This is useful when using a separate API 4 | // endpoint in development than in production. 5 | // 6 | // window.ENV.public_key = '123456' 7 | -------------------------------------------------------------------------------- /tasks/options/imagemin.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | dist: { 3 | files: [{ 4 | expand: true, 5 | cwd: 'tmp/result', 6 | src: '**/*.{png,gif,jpg,jpeg}', 7 | dest: 'dist/' 8 | }] 9 | } 10 | }; -------------------------------------------------------------------------------- /tests/test_loader.js: -------------------------------------------------------------------------------- 1 | // TODO: load based on params 2 | Ember.keys(requirejs._eak_seen).filter(function(key) { 3 | return (/\_test/).test(key); 4 | }).forEach(function(moduleName) { 5 | require(moduleName, null, null, true); 6 | }); 7 | -------------------------------------------------------------------------------- /app/models/message.js: -------------------------------------------------------------------------------- 1 | var attr = DS.attr; 2 | var belongsTo = DS.belongsTo; 3 | 4 | var Message = DS.Model.extend({ 5 | body: attr(), 6 | userName: attr(), 7 | channel: belongsTo('channel') 8 | }); 9 | 10 | export default Message; 11 | -------------------------------------------------------------------------------- /app/components/pretty-color.js: -------------------------------------------------------------------------------- 1 | export default Ember.Component.extend({ 2 | classNames: ['pretty-color'], 3 | attributeBindings: ['style'], 4 | style: function(){ 5 | return 'color: ' + this.get('name') + ';'; 6 | }.property('name') 7 | }); 8 | -------------------------------------------------------------------------------- /public/humans.txt: -------------------------------------------------------------------------------- 1 | # humanstxt.org/ 2 | # The humans responsible & technology colophon 3 | 4 | # TEAM 5 | 6 | -- -- 7 | 8 | # THANKS 9 | 10 | 11 | 12 | # TECHNOLOGY COLOPHON 13 | 14 | HTML5, CSS3 15 | Ember.js 16 | -------------------------------------------------------------------------------- /tasks/options/less.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | compile: { 3 | files: [{ 4 | expand: true, 5 | cwd: 'app/styles', 6 | src: ['**/*.less', '!**/_*.less'], 7 | dest: 'tmp/result/assets/', 8 | ext: '.css' 9 | }] 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /tasks/options/stylus.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | compile: { 3 | files: [{ 4 | expand: true, 5 | cwd: 'app/styles', 6 | src: ['**/*.styl', '!**/_*.styl'], 7 | dest: 'tmp/result/assets/', 8 | ext: '.css' 9 | }] 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /tasks/options/express-server.js: -------------------------------------------------------------------------------- 1 | var grunt = require('grunt'); 2 | 3 | module.exports = { 4 | options: { 5 | APIMethod: "<%= package.APIMethod %>", // stub or proxy 6 | proxyURL: "<%= package.proxyURL %>" // URL to the API server, if using APIMethod: 'proxy' 7 | } 8 | }; -------------------------------------------------------------------------------- /tasks/options/htmlmin.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | dist: { 3 | options: { 4 | removeComments: true, 5 | collapseWhitespace: true 6 | }, 7 | files: [{ 8 | src: 'dist/index.html', 9 | dest: 'dist/index.html' 10 | }] 11 | } 12 | }; -------------------------------------------------------------------------------- /tasks/options/sass.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | compile: { 3 | files: [{ 4 | expand: true, 5 | cwd: 'app/styles', 6 | src: ['**/*.{scss,sass}', '!**/_*.{scss,sass}'], 7 | dest: 'tmp/result/assets/', 8 | ext: '.css' 9 | }] 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /tasks/options/rev.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | dist: { 3 | files: { 4 | src: [ 5 | 'dist/assets/config.min.js', 6 | 'dist/assets/app.min.js', 7 | 'dist/assets/vendor.min.js', 8 | 'dist/assets/app.min.css' 9 | ] 10 | } 11 | } 12 | }; 13 | -------------------------------------------------------------------------------- /app/routes/index.js: -------------------------------------------------------------------------------- 1 | export default Ember.Route.extend({ 2 | model: function() { 3 | return this.store.find('channel', 1); 4 | }, 5 | 6 | afterModel: function() { 7 | var name = prompt("Welcome to Lagerfeuer! Your name:"); 8 | this.controllerFor('user').set('model', {name: name}); 9 | } 10 | }); 11 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | chunky_png (1.2.9) 5 | compass (0.12.2) 6 | chunky_png (~> 1.2) 7 | fssm (>= 0.2.7) 8 | sass (~> 3.1) 9 | fssm (0.2.10) 10 | sass (3.2.13) 11 | 12 | PLATFORMS 13 | ruby 14 | 15 | DEPENDENCIES 16 | compass (~> 0.12.2) 17 | -------------------------------------------------------------------------------- /config/environment.js: -------------------------------------------------------------------------------- 1 | // Put general configuration here. This file is included 2 | // in both production and development BEFORE Ember is 3 | // loaded. 4 | // 5 | // For example to enable a feature on a canary build you 6 | // might do: 7 | // 8 | // window.ENV = {FEATURES: {'with-controller': true}}; 9 | 10 | window.ENV = {}; 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | 7 | # dependencies 8 | /node_modules 9 | /vendor/* 10 | !/vendor/loader.js 11 | 12 | # misc 13 | /.sass-cache 14 | /connect.lock 15 | /libpeerconnection.log 16 | .DS_Store 17 | Thumbs.db 18 | /coverage/* 19 | -------------------------------------------------------------------------------- /app/router.js: -------------------------------------------------------------------------------- 1 | var Router = Ember.Router.extend(); // ensure we don't share routes between all Router instances 2 | 3 | Router.map(function() { 4 | this.route('component-test'); 5 | this.route('helper-test'); 6 | // this.resource('posts', function() { 7 | // this.route('new'); 8 | // }); 9 | }); 10 | 11 | export default Router; 12 | -------------------------------------------------------------------------------- /app/templates/index.hbs: -------------------------------------------------------------------------------- 1 |
2 |
3 |

4 | #stahlstadt.js 5 |

6 |
7 |
8 | 9 | {{#each messages}} 10 | {{render 'message' this}} 11 | {{/each}} 12 | {{markdown-textfield value=message action='sendMessage' upArrowAction='editLastMessage'}} 13 | -------------------------------------------------------------------------------- /app/helpers/markdown-text.js: -------------------------------------------------------------------------------- 1 | marked.setOptions({ 2 | highlight: function(code) { 3 | return hljs.highlightAuto(code).value; 4 | } 5 | }); 6 | 7 | export default Ember.Handlebars.makeBoundHelper(function(input) { 8 | if (input != null) { 9 | var markdown = marked(input); 10 | return new Ember.Handlebars.SafeString(markdown); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /app/helpers/reverse-word.js: -------------------------------------------------------------------------------- 1 | // Please note that Handlebars helpers will only be found automatically by the 2 | // resolver if their name contains a dash (reverse-word, translate-text, etc.) 3 | // For more details: http://stefanpenner.github.io/ember-app-kit/guides/using-modules.html 4 | 5 | export default Ember.Handlebars.makeBoundHelper(function(word) { 6 | return word.split('').reverse().join(''); 7 | }); 8 | 9 | -------------------------------------------------------------------------------- /tests/acceptance/helper_test.js: -------------------------------------------------------------------------------- 1 | var App; 2 | 3 | module("Acceptances - Helper", { 4 | setup: function(){ 5 | App = startApp(); 6 | }, 7 | teardown: function() { 8 | Ember.run(App, 'destroy'); 9 | } 10 | }); 11 | 12 | test("helper output is rendered", function(){ 13 | expect(1); 14 | 15 | visit('/helper-test').then(function(){ 16 | ok(exists("h3:contains('My name is Ember.')")); 17 | }); 18 | }); 19 | 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Coming soon. 2 | 3 | You have to apply this patch yourself after installing packages via bower until foundation 5.0.3 gets released. 4 | 5 | https://github.com/seantimm/foundation/commit/d98a7d540ee764e79d2dbadc0e2617964207a53c 6 | 7 | Execute the following to apply the patch to the `vendor/foundation/js/foundation.js` file: 8 | 9 | curl http://git.io/N4xapA |sed "s/js\/foundation/vendor\/foundation\/js/g" |g apply 10 | -------------------------------------------------------------------------------- /tasks/options/emblem.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | compile: { 3 | files: { 4 | "tmp/result/assets/templates.js": ['app/templates/**/*.{emblem,hbs,hjs,handlebars}'] 5 | }, 6 | options: { 7 | root: 'app/templates/', 8 | dependencies: { 9 | jquery: 'vendor/jquery/jquery.js', 10 | ember: 'vendor/ember/ember.js', 11 | handlebars: 'vendor/handlebars/handlebars.js', 12 | emblem: 'vendor/emblem.js/emblem.js' 13 | } 14 | } 15 | } 16 | }; -------------------------------------------------------------------------------- /app/styles/app.scss: -------------------------------------------------------------------------------- 1 | @import "settings"; 2 | @import "../vendor/foundation/css/foundation.min.css"; 3 | 4 | $fa-font-path: '../vendor/font-awesome/fonts'; 5 | @import "../vendor/font-awesome/scss/font-awesome.scss"; 6 | 7 | 8 | .main-section { 9 | margin-top: 60px; // because navbar is fixed and 45px high. 10 | } 11 | 12 | .message { 13 | margin-top: 10px; 14 | } 15 | 16 | code { 17 | margin-top: 5px; 18 | margin-bottom: 5px; 19 | font-size: 80%; 20 | font-weight: lighter; 21 | } 22 | -------------------------------------------------------------------------------- /tests/unit/routes/index_test.js: -------------------------------------------------------------------------------- 1 | import Index from 'appkit/routes/index'; 2 | 3 | var route; 4 | module("Unit - IndexRoute", { 5 | setup: function(){ 6 | var container = isolatedContainer([ 7 | 'route:index' 8 | ]); 9 | 10 | route = container.lookup('route:index'); 11 | } 12 | }); 13 | 14 | test("it exists", function(){ 15 | ok(route); 16 | ok(route instanceof Index); 17 | }); 18 | 19 | test("#model", function(){ 20 | deepEqual(route.model(), ['red', 'yellow', 'blue']); 21 | }); 22 | -------------------------------------------------------------------------------- /tasks/options/jshint.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | app: { 3 | src: [ 4 | 'app/**/*.js' 5 | ], 6 | options: { jshintrc: '.jshintrc' } 7 | }, 8 | 9 | tooling: { 10 | src: [ 11 | 'Gruntfile.js', 12 | 'tasks/**/*.js' 13 | ], 14 | options: { jshintrc: 'tasks/.jshintrc' } 15 | }, 16 | 17 | tests: { 18 | src: [ 19 | 'tests/**/*.js', 20 | ], 21 | options: { jshintrc: 'tests/.jshintrc' } 22 | }, 23 | 24 | options: { 25 | force: true 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /tests/acceptance/index_test.js: -------------------------------------------------------------------------------- 1 | var App; 2 | 3 | module('Acceptances - Index', { 4 | setup: function(){ 5 | App = startApp(); 6 | }, 7 | teardown: function() { 8 | Ember.run(App, 'destroy'); 9 | } 10 | }); 11 | 12 | test('index renders', function(){ 13 | expect(3); 14 | 15 | visit('/').then(function(){ 16 | var title = find('h2#title'); 17 | var list = find('ul li'); 18 | 19 | equal(title.text(), 'Welcome to Ember.js'); 20 | 21 | equal(list.length, 3); 22 | equal(list.text(), 'redyellowblue'); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /tasks/options/compass.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | options: { 3 | sassDir: "app/styles", 4 | cssDir: "tmp/result/assets", 5 | generatedImagesDir: "tmp/result/assets/images/generated", 6 | imagesDir: "public/assets/images", 7 | javascriptsDir: "app", 8 | fontsDir: "public/assets/fonts", 9 | importPath: ["vendor"], 10 | httpImagesPath: "/assets/images", 11 | httpGeneratedImagesPath: "/assets/images/generated", 12 | httpFontsPath: "/assets/fonts", 13 | relativeAssets: false, 14 | debugInfo: true 15 | }, 16 | compile: {} 17 | }; 18 | -------------------------------------------------------------------------------- /tasks/options/concat_sourcemap.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | app: { 3 | src: ['tmp/transpiled/app/**/*.js'], 4 | dest: 'tmp/result/assets/app.js', 5 | options: { 6 | sourcesContent: true 7 | }, 8 | }, 9 | 10 | config: { 11 | src: ['tmp/result/config/**/*.js'], 12 | dest: 'tmp/result/assets/config.js', 13 | options: { 14 | sourcesContent: true 15 | }, 16 | }, 17 | 18 | test: { 19 | src: 'tmp/transpiled/tests/**/*.js', 20 | dest: 'tmp/result/tests/tests.js', 21 | options: { 22 | sourcesContent: true 23 | } 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /tests/acceptance/component_test.js: -------------------------------------------------------------------------------- 1 | var App; 2 | 3 | module('Acceptances - Component', { 4 | setup: function(){ 5 | App = startApp(); 6 | }, 7 | teardown: function() { 8 | Ember.run(App, 'destroy'); 9 | } 10 | }); 11 | 12 | test('component output is rendered', function(){ 13 | expect(3); 14 | 15 | visit('/component-test').then(function(){ 16 | var title = find('h2#title'); 17 | var list = find('.pretty-color'); 18 | 19 | equal(title.text(), 'Welcome to Ember.js'); 20 | 21 | equal(list.length, 3); 22 | equal(list.first().text(), 'Pretty Color: purple\n'); 23 | }); 24 | }); 25 | 26 | -------------------------------------------------------------------------------- /tasks/locking.js: -------------------------------------------------------------------------------- 1 | var lockFile = require('lockfile'); 2 | 3 | module.exports = function(grunt) { 4 | grunt.registerTask('lock', 'Set semaphore for connect server to wait on.', function() { 5 | grunt.file.mkdir('tmp'); 6 | lockFile.lockSync('tmp/connect.lock'); 7 | grunt.log.writeln("Locked - Development server won't answer incoming requests until App Kit is done updating."); 8 | }); 9 | 10 | grunt.registerTask('unlock', 'Release semaphore that connect server waits on.', function() { 11 | lockFile.unlockSync('tmp/connect.lock'); 12 | grunt.log.writeln("Unlocked - Development server now handles requests."); 13 | }); 14 | }; 15 | -------------------------------------------------------------------------------- /public/crossdomain.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 15 | 16 | -------------------------------------------------------------------------------- /app/controllers/message.js: -------------------------------------------------------------------------------- 1 | export default Ember.ObjectController.extend({ 2 | cancelEdit: function() { 3 | this.set('editing', false); 4 | }, 5 | 6 | actions: { 7 | edit: function() { 8 | this.set('editing', true); 9 | }, 10 | 11 | cancelEdit: function() { 12 | this.get('model').rollback(); 13 | this.cancelEdit(); 14 | }, 15 | 16 | persistEdit: function() { 17 | var message = this.get('model'); 18 | 19 | message.save().then(this.cancelEdit.bind(this)); 20 | }, 21 | 22 | delete: function() { 23 | if (confirm('Delete this message?')) { 24 | this.send('deleteMessage', this.get('model')); 25 | } 26 | } 27 | } 28 | }); 29 | -------------------------------------------------------------------------------- /tasks/options/preprocess.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | indexHTMLDebugApp: { 3 | src : 'app/index.html', dest : 'tmp/result/index.html', 4 | options: { context: { dist: false, tests: false } } 5 | }, 6 | indexHTMLDebugTests: { 7 | src : 'app/index.html', dest : 'tmp/result/tests/index.html', 8 | options: { context: { dist: false, tests: true } } 9 | }, 10 | indexHTMLDistApp: { 11 | src : 'app/index.html', dest : 'tmp/result/index.html', 12 | options: { context: { dist: true, tests: false } } 13 | }, 14 | indexHTMLDistTests: { 15 | src : 'app/index.html', dest : 'tmp/result/tests/index.html', 16 | options: { context: { dist: true, tests: true } } 17 | } 18 | }; -------------------------------------------------------------------------------- /tasks/options/fancySprites.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | 3 | module.exports = { 4 | create: { 5 | destStyles: 'tmp/sprites', 6 | destSpriteSheets: 'tmp/result/assets/sprites', 7 | files: [{ 8 | src: ['app/sprites/**/*.{png,jpg,jpeg}', '!app/sprites/**/*@2x.{png,jpg,jpeg}'], 9 | spriteSheetName: '1x', 10 | spriteName: function(name) { 11 | return path.basename(name, path.extname(name)); 12 | } 13 | }, { 14 | src: 'app/sprites/**/*@2x.{png,jpg,jpeg}', 15 | spriteSheetName: '2x', 16 | spriteName: function(name) { 17 | return path.basename(name, path.extname(name)).replace(/@2x/, ''); 18 | } 19 | } 20 | ] 21 | } 22 | }; -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ember-app-kit", 3 | "dependencies": { 4 | "handlebars": "~1.1.2", 5 | "jquery": "~1.9.1", 6 | "qunit": "~1.12.0", 7 | "ember": "~1.3.0-beta.4", 8 | "ember-data": "~1.0.0-beta.4", 9 | "ember-resolver": "git://github.com/stefanpenner/ember-jj-abrams-resolver.git#master", 10 | "ic-ajax": "~0.2", 11 | "ember-testing-httpRespond": "~0.1.1", 12 | "sockjs": "~0.3.4", 13 | "marked": "~0.3.0", 14 | "highlightjs": "~7.5.0", 15 | "vertx": "http://dl.bintray.com/vertx/downloads/vert.x-2.1M2.zip", 16 | "foundation": "~5.0.2", 17 | "font-awesome": "~4.0.3" 18 | }, 19 | "resolutions": { 20 | "ember": "~1.3.0-beta.4", 21 | "jquery": ">= 2.0.0" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "predef": [ 3 | "document", 4 | "window", 5 | "location", 6 | "setTimeout", 7 | "Ember", 8 | "Em", 9 | "DS", 10 | "$" 11 | ], 12 | "node" : false, 13 | "browser" : false, 14 | "boss" : true, 15 | "curly": false, 16 | "debug": false, 17 | "devel": false, 18 | "eqeqeq": true, 19 | "evil": true, 20 | "forin": false, 21 | "immed": false, 22 | "laxbreak": false, 23 | "newcap": true, 24 | "noarg": true, 25 | "noempty": false, 26 | "nonew": false, 27 | "nomen": false, 28 | "onevar": false, 29 | "plusplus": false, 30 | "regexp": false, 31 | "undef": true, 32 | "sub": true, 33 | "strict": false, 34 | "white": false, 35 | "eqnull": true, 36 | "esnext": true 37 | } 38 | -------------------------------------------------------------------------------- /app/templates/application.hbs: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 9 |
10 | 17 | 18 |
19 |
20 |
21 | {{outlet}} 22 |
23 |
24 |
25 | 26 |
27 | -------------------------------------------------------------------------------- /tasks/options/transpile.js: -------------------------------------------------------------------------------- 1 | var grunt = require('grunt'); 2 | 3 | module.exports = { 4 | "tests": { 5 | type: 'amd', 6 | moduleName: function(path) { 7 | return grunt.config.process('<%= package.namespace %>/tests/') + path; 8 | }, 9 | files: [{ 10 | expand: true, 11 | cwd: 'tmp/javascript/tests/', 12 | src: '**/*.js', 13 | dest: 'tmp/transpiled/tests/' 14 | }] 15 | }, 16 | "app": { 17 | type: 'amd', 18 | moduleName: function(path) { 19 | return grunt.config.process('<%= package.namespace %>/') + path; 20 | }, 21 | files: [{ 22 | expand: true, 23 | cwd: 'tmp/javascript/app/', 24 | src: '**/*.js', 25 | dest: 'tmp/transpiled/app/' 26 | }] 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /tasks/options/emberTemplates.js: -------------------------------------------------------------------------------- 1 | var grunt = require('grunt'); 2 | 3 | module.exports = { 4 | options: { 5 | templateBasePath: /app\//, 6 | templateFileExtensions: /\.(hbs|hjs|handlebars)/, 7 | templateRegistration: function(name, template) { 8 | return grunt.config.process("define('<%= package.namespace %>/") + name + "', ['exports'], function(__exports__){ __exports__['default'] = " + template + "; });"; 9 | } 10 | }, 11 | debug: { 12 | options: { 13 | precompile: false 14 | }, 15 | src: "app/templates/**/*.{hbs,hjs,handlebars}", 16 | dest: "tmp/result/assets/templates.js" 17 | }, 18 | dist: { 19 | src: "<%= emberTemplates.debug.src %>", 20 | dest: "<%= emberTemplates.debug.dest %>" 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /api-stub/routes.js: -------------------------------------------------------------------------------- 1 | module.exports = function(server) { 2 | 3 | // Create an API namespace, so that the root does not 4 | // have to be repeated for each end point. 5 | server.namespace('/api', function() { 6 | 7 | // Return fixture data for '/api/posts/:id' 8 | server.get('/posts/:id', function(req, res) { 9 | var post = { 10 | "post": { 11 | "id": 1, 12 | "title": "Rails is omakase", 13 | "comments": ["1", "2"], 14 | "user" : "dhh" 15 | }, 16 | 17 | "comments": [{ 18 | "id": "1", 19 | "body": "Rails is unagi" 20 | }, { 21 | "id": "2", 22 | "body": "Omakase O_o" 23 | }] 24 | }; 25 | 26 | res.send(post); 27 | }); 28 | 29 | }); 30 | 31 | }; -------------------------------------------------------------------------------- /tests/helpers/start_app.js: -------------------------------------------------------------------------------- 1 | import Application from 'appkit/app'; 2 | import Router from 'appkit/router'; 3 | 4 | function startApp(attrs) { 5 | var App; 6 | 7 | var attributes = Ember.merge({ 8 | // useful Test defaults 9 | rootElement: '#ember-testing', 10 | LOG_ACTIVE_GENERATION:false, 11 | LOG_VIEW_LOOKUPS: false 12 | }, attrs); // but you can override; 13 | 14 | Router.reopen({ 15 | location: 'none' 16 | }); 17 | 18 | Ember.run(function(){ 19 | App = Application.create(attributes); 20 | App.setupForTesting(); 21 | App.injectTestHelpers(); 22 | }); 23 | 24 | App.reset(); // this shouldn't be needed, i want to be able to "start an app at a specific URL" 25 | 26 | return App; 27 | } 28 | 29 | export default startApp; 30 | -------------------------------------------------------------------------------- /app/app.js: -------------------------------------------------------------------------------- 1 | import Resolver from 'resolver'; 2 | 3 | var App = Ember.Application.extend({ 4 | LOG_ACTIVE_GENERATION: true, 5 | LOG_MODULE_RESOLVER: true, 6 | LOG_TRANSITIONS: true, 7 | LOG_TRANSITIONS_INTERNAL: true, 8 | LOG_VIEW_LOOKUPS: true, 9 | modulePrefix: 'appkit', // TODO: loaded via config 10 | Resolver: Resolver['default'], 11 | ready: function() { 12 | $(document).foundation(); // init foundation.js 13 | } 14 | }); 15 | 16 | Ember.RSVP.configure('onerror', function(error) { 17 | // ensure unhandled promises raise awareness. 18 | // may result in false negatives, but visibility is more important 19 | if (error instanceof Error) { 20 | Ember.Logger.assert(false, error); 21 | Ember.Logger.error(error.stack); 22 | } 23 | }); 24 | 25 | export default App; 26 | -------------------------------------------------------------------------------- /tests/helpers/isolated_container.js: -------------------------------------------------------------------------------- 1 | import Resolver from 'resolver'; 2 | 3 | function isolatedContainer(fullNames) { 4 | var container = new Ember.Container(); 5 | 6 | container.optionsForType('component', { singleton: false }); 7 | container.optionsForType('view', { singleton: false }); 8 | container.optionsForType('template', { instantiate: false }); 9 | container.optionsForType('helper', { instantiate: false }); 10 | 11 | var resolver = Resolver['default'].create(); 12 | 13 | resolver.namespace = { 14 | modulePrefix: 'appkit' 15 | }; 16 | 17 | for (var i = fullNames.length; i > 0; i--) { 18 | var fullName = fullNames[i - 1]; 19 | container.register(fullName, resolver.resolve(fullName)); 20 | } 21 | 22 | return container; 23 | } 24 | 25 | export default isolatedContainer; 26 | -------------------------------------------------------------------------------- /app/components/markdown-textfield.js: -------------------------------------------------------------------------------- 1 | // Ember.TextArea extends Ember.Component so we don't have to specify 2 | // a template if we just want to use a normal textarea in our view. 3 | 4 | export default Ember.TextArea.extend({ 5 | classNames: ['md-textfield'], 6 | 7 | placeholder: 'Say something', 8 | 9 | rows: 1, 10 | 11 | // When pressing alt + enter the TextArea will grow. Otherwise when hitting 12 | // enter the TextArea will behave in the default way. 13 | insertNewline: function(event) { 14 | if (event.altKey) { 15 | this.incrementProperty('rows'); 16 | } else { 17 | this._super(event); 18 | this.set('rows', 1); 19 | } 20 | }, 21 | 22 | keyDown: function(event) { 23 | var insertedText = this.get('value'); 24 | var upArrowPressed = event.keyCode === 38; 25 | 26 | if ((insertedText == null || insertedText.length === 0) && upArrowPressed) { 27 | this.sendAction('upArrowAction'); 28 | } 29 | } 30 | }); 31 | -------------------------------------------------------------------------------- /tasks/options/emberscript.js: -------------------------------------------------------------------------------- 1 | // EmberScript compilation. This must be enabled by modification 2 | // of Gruntfile.js. 3 | // 4 | // The `bare` option is used since this file will be transpiled 5 | // anyway. In EmberScript files, you need to escape out for 6 | // some ES6 features like import and export. For example: 7 | // 8 | // `import User from 'appkit/models/user'` 9 | // 10 | // class Post 11 | // init: (userId) -> 12 | // @user = User.findById(userId) 13 | // 14 | // `export default Post` 15 | // 16 | 17 | module.exports = { 18 | "test": { 19 | options: { 20 | bare: true 21 | }, 22 | files: [{ 23 | expand: true, 24 | cwd: 'tests/', 25 | src: '**/*.em', 26 | dest: 'tmp/javascript/tests', 27 | ext: '.js' 28 | }] 29 | }, 30 | "app": { 31 | options: { 32 | bare: true 33 | }, 34 | files: [{ 35 | expand: true, 36 | cwd: 'app/', 37 | src: '**/*.em', 38 | dest: 'tmp/javascript/app', 39 | ext: '.js' 40 | }] 41 | } 42 | }; -------------------------------------------------------------------------------- /tests/test_helper.js: -------------------------------------------------------------------------------- 1 | document.write('
'); 2 | 3 | Ember.testing = true; 4 | 5 | window.startApp = require('appkit/tests/helpers/start_app')['default']; 6 | window.isolatedContainer = require('appkit/tests/helpers/isolated_container')['default']; 7 | 8 | function exists(selector) { 9 | return !!find(selector).length; 10 | } 11 | 12 | function getAssertionMessage(actual, expected, message) { 13 | return message || QUnit.jsDump.parse(expected) + " expected but was " + QUnit.jsDump.parse(actual); 14 | } 15 | 16 | function equal(actual, expected, message) { 17 | message = getAssertionMessage(actual, expected, message); 18 | QUnit.equal.call(this, actual, expected, message); 19 | } 20 | 21 | function strictEqual(actual, expected, message) { 22 | message = getAssertionMessage(actual, expected, message); 23 | QUnit.strictEqual.call(this, actual, expected, message); 24 | } 25 | 26 | window.exists = exists; 27 | window.equal = equal; 28 | window.strictEqual = strictEqual; 29 | -------------------------------------------------------------------------------- /tasks/options/coffee.js: -------------------------------------------------------------------------------- 1 | // CoffeeScript compilation. This must be enabled by modification 2 | // of Gruntfile.js. 3 | // 4 | // The `bare` option is used since this file will be transpiled 5 | // anyway. In CoffeeScript files, you need to escape out for 6 | // some ES6 features like import and export. For example: 7 | // 8 | // `import User from 'appkit/models/user'` 9 | // 10 | // Post = Em.Object.extend 11 | // init: (userId) -> 12 | // @set 'user', User.findById(userId) 13 | // 14 | // `export default Post` 15 | // 16 | 17 | module.exports = { 18 | "test": { 19 | options: { 20 | bare: true 21 | }, 22 | files: [{ 23 | expand: true, 24 | cwd: 'tests/', 25 | src: '**/*.coffee', 26 | dest: 'tmp/javascript/tests', 27 | ext: '.js' 28 | }] 29 | }, 30 | "app": { 31 | options: { 32 | bare: true 33 | }, 34 | files: [{ 35 | expand: true, 36 | cwd: 'app/', 37 | src: '**/*.coffee', 38 | dest: 'tmp/javascript/app', 39 | ext: '.js' 40 | }] 41 | } 42 | }; 43 | -------------------------------------------------------------------------------- /app/templates/message.hbs: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 |
6 |
7 | {{#if editing}} 8 |
9 |
10 | {{markdown-textfield value=body action='persistEdit'}} 11 |
12 |
13 | cancel 14 |
15 |
16 | {{else}} 17 |
18 |
19 | {{userName}} 20 | 8:54 am 21 |
{{markdown-text body}}
22 |
23 |
24 |
25 | 26 | 27 |
28 | {{/if}} 29 |
30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Michael Klein and lagerfeuer-ember contributors. 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /app/controllers/event_bus.js: -------------------------------------------------------------------------------- 1 | export default Ember.ObjectController.extend(Ember.Evented, { 2 | connectEventBus: function() { 3 | var eb = new vertx.EventBus("http://localhost:3000/eventbus"); 4 | eb.onopen = this.announceEventbusReady.bind(this); 5 | 6 | this.set('model', eb); 7 | }, 8 | 9 | eventbus: Em.computed.alias('model'), 10 | 11 | handlerQueue: [], 12 | 13 | queueHandler: function(handlerObject) { 14 | if (this.get('eventbusReady')) { 15 | this.registerHandler(handlerObject); 16 | } else { 17 | this.get('handlerQueue').pushObject(handlerObject); 18 | } 19 | }, 20 | 21 | registerHandler: function(handlerObject) { 22 | var address = handlerObject.address; 23 | var handler = handlerObject.handler; 24 | var eventbus = this.get('eventbus'); 25 | 26 | eventbus.registerHandler(address, handler); 27 | }, 28 | 29 | registerQueuedHandlers: function() { 30 | var registerHandler = this.registerHandler.bind(this); 31 | this.get('handlerQueue').forEach(registerHandler); 32 | }.on('eventbusReady'), 33 | 34 | setEventbusReady: function() { 35 | this.set('eventbusReady', true); 36 | }.on('eventbusReady'), 37 | 38 | announceEventbusReady: function() { 39 | this.trigger('eventbusReady'); 40 | } 41 | }); 42 | -------------------------------------------------------------------------------- /tasks/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "predef": [ 3 | "document", 4 | "window", 5 | "location", 6 | "setTimeout", 7 | "Ember", 8 | "Em", 9 | "$", 10 | "QUnit", 11 | "define", 12 | "console", 13 | "require", 14 | "requirejs", 15 | "equal", 16 | "notEqual", 17 | "notStrictEqual", 18 | "test", 19 | "asyncTest", 20 | "testBoth", 21 | "testWithDefault", 22 | "raises", 23 | "throws", 24 | "deepEqual", 25 | "start", 26 | "stop", 27 | "ok", 28 | "strictEqual", 29 | "module", 30 | "process", 31 | "expect", 32 | "visit", 33 | "exists", 34 | "fillIn", 35 | "click", 36 | "find", 37 | "isolatedContainer", 38 | "startApp", 39 | "__dirname" 40 | ], 41 | "node" : false, 42 | "browser" : false, 43 | "boss" : true, 44 | "curly": false, 45 | "debug": false, 46 | "devel": false, 47 | "eqeqeq": true, 48 | "evil": true, 49 | "forin": false, 50 | "immed": false, 51 | "laxbreak": false, 52 | "newcap": true, 53 | "noarg": true, 54 | "noempty": false, 55 | "nonew": false, 56 | "nomen": false, 57 | "onevar": false, 58 | "plusplus": false, 59 | "regexp": false, 60 | "undef": true, 61 | "sub": true, 62 | "strict": false, 63 | "white": false, 64 | "eqnull": true, 65 | "esnext": true 66 | } 67 | -------------------------------------------------------------------------------- /tests/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "predef": [ 3 | "document", 4 | "window", 5 | "location", 6 | "setTimeout", 7 | "Ember", 8 | "Em", 9 | "$", 10 | "QUnit", 11 | "define", 12 | "console", 13 | "require", 14 | "requirejs", 15 | "equal", 16 | "notEqual", 17 | "notStrictEqual", 18 | "test", 19 | "asyncTest", 20 | "testBoth", 21 | "testWithDefault", 22 | "raises", 23 | "throws", 24 | "deepEqual", 25 | "start", 26 | "stop", 27 | "ok", 28 | "strictEqual", 29 | "module", 30 | "process", 31 | "expect", 32 | "visit", 33 | "exists", 34 | "fillIn", 35 | "click", 36 | "keyEvent", 37 | "find", 38 | "wait", 39 | "keyEvent", 40 | "isolatedContainer", 41 | "startApp" 42 | ], 43 | "node" : false, 44 | "browser" : false, 45 | "boss" : true, 46 | "curly": false, 47 | "debug": false, 48 | "devel": false, 49 | "eqeqeq": true, 50 | "evil": true, 51 | "forin": false, 52 | "immed": false, 53 | "laxbreak": false, 54 | "newcap": true, 55 | "noarg": true, 56 | "noempty": false, 57 | "nonew": false, 58 | "nomen": false, 59 | "onevar": false, 60 | "plusplus": false, 61 | "regexp": false, 62 | "undef": true, 63 | "sub": true, 64 | "strict": false, 65 | "white": false, 66 | "eqnull": true, 67 | "esnext": true 68 | } 69 | -------------------------------------------------------------------------------- /tasks/options/watch.js: -------------------------------------------------------------------------------- 1 | var Helpers = require('../helpers'), 2 | filterAvailable = Helpers.filterAvailableTasks; 3 | 4 | var scripts = '{app,tests}/**/*.{js,coffee,em}', 5 | templates = 'app/templates/**/*.{hbs,handlebars,hjs,emblem}', 6 | sprites = 'app/sprites/**/*.{png,jpg,jpeg}', 7 | styles = 'app/styles/**/*.{css,sass,scss,less,styl}', 8 | indexHTML = 'app/index.html', 9 | other = '{app,tests,public,vendor}/**/*'; 10 | 11 | module.exports = { 12 | scripts: { 13 | files: [scripts], 14 | tasks: ['lock', 'buildScripts', 'unlock'] 15 | }, 16 | templates: { 17 | files: [templates], 18 | tasks: ['lock', 'buildTemplates:debug', 'unlock'] 19 | }, 20 | sprites: { 21 | files: [sprites], 22 | tasks: filterAvailable(['lock', 'fancySprites:create', 'unlock']) 23 | }, 24 | styles: { 25 | files: [styles], 26 | tasks: ['lock', 'buildStyles', 'unlock'] 27 | }, 28 | indexHTML: { 29 | files: [indexHTML], 30 | tasks: ['lock', 'buildIndexHTML:debug', 'unlock'] 31 | }, 32 | other: { 33 | files: [other, '!'+scripts, '!'+templates, '!'+styles, '!'+indexHTML], 34 | tasks: ['lock', 'build:debug', 'unlock'] 35 | }, 36 | 37 | options: { 38 | // No need to debounce 39 | debounceDelay: 0, 40 | // When we don't have inotify 41 | interval: 100, 42 | livereload: Helpers.isPackageAvailable("connect-livereload") 43 | } 44 | }; 45 | -------------------------------------------------------------------------------- /vendor/loader.js: -------------------------------------------------------------------------------- 1 | var define, requireModule, require, requirejs; 2 | 3 | (function() { 4 | var registry = {}, seen = {}; 5 | 6 | define = function(name, deps, callback) { 7 | registry[name] = { deps: deps, callback: callback }; 8 | }; 9 | 10 | requirejs = require = requireModule = function(name) { 11 | requirejs._eak_seen = registry; 12 | 13 | if (seen.hasOwnProperty(name)) { return seen[name]; } 14 | seen[name] = {}; 15 | 16 | if (!registry[name]) { 17 | throw new Error("Could not find module " + name); 18 | } 19 | 20 | var mod = registry[name], 21 | deps = mod.deps, 22 | callback = mod.callback, 23 | reified = [], 24 | exports; 25 | 26 | for (var i=0, l=deps.length; i 0) { 35 | var msg = { body: message, address: address, user_name: user_name, user_id: 1 }; 36 | 37 | this.get('eb.model').send('chat.send_message', msg); 38 | this.set('message', ''); 39 | } 40 | }, 41 | 42 | deleteMessage: function(message) { 43 | message.destroyRecord().then(this.removeMessage.bind(this)); 44 | }, 45 | 46 | editLastMessage: function() { 47 | console.log('editing messages is not supported yet'); 48 | } 49 | } 50 | }); 51 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app-kit", 3 | "namespace": "appkit", 4 | "APIMethod": "stub", 5 | "proxyURL": "http://localhost:8000", 6 | "version": "0.0.0", 7 | "private": true, 8 | "directories": { 9 | "doc": "doc", 10 | "test": "test" 11 | }, 12 | "scripts": { 13 | "start": "grunt server", 14 | "build": "grunt build:debug", 15 | "test": "grunt test:ci", 16 | "postinstall": "bower install" 17 | }, 18 | "repository": { 19 | "type": "git", 20 | "url": "git://github.com/stefanpenner/ember-app-kit.git" 21 | }, 22 | "author": "", 23 | "license": "MIT", 24 | "devDependencies": { 25 | "express": "~3.4.2", 26 | "lockfile": "~>0.3.0", 27 | "bower": "~1.2.7", 28 | "grunt": "~0.4.2", 29 | "grunt-cli": "~0.1.9", 30 | "load-grunt-config": "git://github.com/Pradeek/load-grunt-config.git", 31 | "grunt-contrib-watch": "~0.5.3", 32 | "grunt-contrib-copy": "~0.4.1", 33 | "grunt-contrib-concat": "~0.3.0", 34 | "grunt-contrib-clean": "~0.4.1", 35 | "grunt-contrib-jshint": "~0.7.2", 36 | "grunt-contrib-uglify": "~0.2.2", 37 | "grunt-contrib-cssmin": "~0.6.1", 38 | "grunt-preprocess": "~3.0.1", 39 | "grunt-es6-module-transpiler": "~0.5.1", 40 | "grunt-concat-sourcemap": "~0.3.0", 41 | "grunt-concurrent": "~0.3.1", 42 | "grunt-usemin": "~0.1.12", 43 | "grunt-rev": "~0.1.0", 44 | "grunt-ember-templates": "~0.4.18", 45 | "grunt-contrib-testem": "~0.5.11", 46 | "express-namespace": "~0.1.1", 47 | "request": "~2.27.0", 48 | "loom-generators-ember-appkit": "~1.0.2", 49 | "originate": "~0.1.5", 50 | "loom": "~3.1.2", 51 | "grunt-contrib-compass": "~0.7.0" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /tasks/helpers.js: -------------------------------------------------------------------------------- 1 | var grunt = require('grunt'), 2 | _ = grunt.util._, 3 | Helpers = {}; 4 | 5 | // List of package requisits for tasks 6 | // Notated in conjunctive normal form (CNF) 7 | // e.g. ['a', ['b', 'alternative-to-b']] 8 | var taskRequirements = { 9 | 'coffee': ['grunt-contrib-coffee'], 10 | 'compass': ['grunt-contrib-compass'], 11 | 'sass': [['grunt-sass', 'grunt-contrib-sass']], 12 | 'less': ['grunt-contrib-less'], 13 | 'stylus': ['grunt-contrib-stylus'], 14 | 'emberTemplates': ['grunt-ember-templates'], 15 | 'emblem': ['grunt-emblem'], 16 | 'emberscript': ['grunt-ember-script'], 17 | 'imagemin': ['grunt-contrib-imagemin'], 18 | 'htmlmin': ['grunt-contrib-htmlmin'], 19 | 'fancySprites': ['grunt-fancy-sprites'] 20 | }; 21 | 22 | // Task fallbacks 23 | // e.g. 'a': ['fallback-a-step-1', 'fallback-a-step-2'] 24 | var taskFallbacks = { 25 | 'imagemin': 'copy:imageminFallback' 26 | }; 27 | 28 | 29 | Helpers.filterAvailableTasks = function(tasks){ 30 | tasks = tasks.map(function(taskName) { 31 | // Maps to task name or fallback if task is unavailable 32 | 33 | var baseName = taskName.split(':')[0]; // e.g. 'coffee' for 'coffee:compile' 34 | var reqs = taskRequirements[baseName]; 35 | var isAvailable = Helpers.isPackageAvailable(reqs); 36 | return isAvailable ? taskName : taskFallbacks[taskName]; 37 | }); 38 | 39 | return _.flatten(_.compact(tasks)); // Remove undefined's and flatten it 40 | }; 41 | 42 | Helpers.isPackageAvailable = function(pkgNames) { 43 | if (!pkgNames) return true; // packages are assumed to exist 44 | 45 | if (!_.isArray(pkgNames)) { pkgNames = [pkgNames]; } 46 | 47 | return _.every(pkgNames, function(pkgNames) { 48 | if (!_.isArray(pkgNames)) { pkgNames = [pkgNames]; } 49 | 50 | return _.any(pkgNames, function(pkgName) { 51 | return !!Helpers.pkg.devDependencies[pkgName]; 52 | }); 53 | }); 54 | }; 55 | 56 | module.exports = Helpers; 57 | -------------------------------------------------------------------------------- /tasks/options/copy.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 3 | // Note: These tasks are listed in the order in which they will run. 4 | 5 | javascriptToTmp: { 6 | files: [{ 7 | expand: true, 8 | cwd: 'app', 9 | src: '**/*.js', 10 | dest: 'tmp/javascript/app' 11 | }, 12 | { 13 | expand: true, 14 | cwd: 'tests', 15 | src: ['**/*.js', '!test_helper.js', '!test_loader.js'], 16 | dest: 'tmp/javascript/tests/' 17 | }] 18 | }, 19 | 20 | cssToResult: { 21 | expand: true, 22 | cwd: 'app/styles', 23 | src: ['**/*.css'], 24 | dest: 'tmp/result/assets' 25 | }, 26 | 27 | // Assembles everything in `tmp/result`. 28 | // The sole purpose of this task is to keep things neat. Gathering everything in one 29 | // place (tmp/dist) enables the subtasks of dist to only look there. Note: However, 30 | // for normal development this is done on the fly by the development server. 31 | assemble: { 32 | files: [{ 33 | expand: true, 34 | cwd: 'tests', 35 | src: ['test_helper.js', 'test_loader.js'], 36 | dest: 'tmp/result/tests/' 37 | }, { 38 | expand: true, 39 | cwd: 'public', 40 | src: ['**'], 41 | dest: 'tmp/result/' 42 | }, { 43 | src: ['vendor/**/*.js', 'vendor/**/*.css'], 44 | dest: 'tmp/result/' 45 | }, { 46 | src: ['config/**/*.js'], 47 | dest: 'tmp/result/' 48 | } 49 | 50 | ] 51 | }, 52 | 53 | imageminFallback: { 54 | files: '<%= imagemin.dist.files %>' 55 | }, 56 | 57 | dist: { 58 | files: [{ 59 | expand: true, 60 | cwd: 'tmp/result', 61 | src: [ 62 | '**', 63 | '!**/*.{css,js}', // Already handled by concat 64 | '!**/*.{png,gif,jpg,jpeg}', // Already handled by imagemin 65 | '!tests/**/*', // No tests, please 66 | '!**/*.map' // No source maps 67 | ], 68 | filter: 'isFile', 69 | dest: 'dist/' 70 | }] 71 | }, 72 | }; 73 | -------------------------------------------------------------------------------- /tasks/options/testem.js: -------------------------------------------------------------------------------- 1 | // See https://npmjs.org/package/grunt-contrib-testem for more config options 2 | module.exports = { 3 | basic: { 4 | options: { 5 | parallel: 2, 6 | framework: 'qunit', 7 | src_files: [ 8 | 'tmp/result/{app,tests}/**/*.{js,coffee,css}', 9 | 'tmp/result/index.html' 10 | ], 11 | serve_files: [ 12 | 'vendor/loader.js', 13 | 'vendor/ember-resolver/dist/ember-resolver.js', 14 | 'vendor/jquery/jquery.js', 15 | 'vendor/handlebars/handlebars.js', 16 | 'vendor/ember/ember.js', 17 | 'vendor/ember-data/ember-data.js', 18 | 'vendor/ic-ajax/main.js', 19 | 'tmp/result/assets/templates.js', 20 | 'tmp/result/assets/app.js', 21 | 'tmp/transpiled/tests/**/*.js', 22 | 'tests/test_helper.js', 23 | 'tests/test_loader.js' 24 | ], 25 | launch_in_dev: ['PhantomJS', 'Chrome'], 26 | launch_in_ci: ['PhantomJS', 'Chrome'], 27 | } 28 | }, 29 | browsers: { 30 | options: { 31 | parallel: 8, 32 | framework: 'qunit', 33 | src_files: [ 34 | 'tmp/result/{app,tests}/**/*.{js,coffee,css}', 35 | 'tmp/result/index.html' 36 | ], 37 | serve_files: [ 38 | 'vendor/loader.js', 39 | 'vendor/ember-resolver/dist/ember-resolver.js', 40 | 'vendor/jquery/jquery.js', 41 | 'vendor/handlebars/handlebars.js', 42 | 'vendor/ember/ember.js', 43 | 'vendor/ember-data/ember-data.js', 44 | 'vendor/ic-ajax/main.js', 45 | 'tmp/result/assets/templates.js', 46 | 'tmp/result/assets/app.js', 47 | 'tmp/transpiled/tests/**/*.js', 48 | 'tests/test_helper.js', 49 | 'tests/test_loader.js' 50 | ], 51 | launch_in_dev: ['PhantomJS', 52 | 'Chrome', 53 | 'ChromeCanary', 54 | 'Firefox', 55 | 'Safari', 56 | 'IE7', 57 | 'IE8', 58 | 'IE9'], 59 | launch_in_ci: ['PhantomJS', 60 | 'Chrome', 61 | 'ChromeCanary', 62 | 'Firefox', 63 | 'Safari', 64 | 'IE7', 65 | 'IE8', 66 | 'IE9'], 67 | } 68 | } 69 | }; 70 | -------------------------------------------------------------------------------- /api-stub/README.md: -------------------------------------------------------------------------------- 1 | API Stub 2 | ======== 3 | 4 | The stub allows you to implement express routes to fake API calls. 5 | Simply add API routes in the routes.js file. The benefit of an API 6 | stub is that you can use the REST adapter from the get go. It's a 7 | way to use fixtures without having to use the fixture adapter. 8 | 9 | As development progresses, the API stub becomes a functioning spec 10 | for the real backend. Once you have a separate development API 11 | server running, then switch from the stub to the proxy pass through. 12 | 13 | To configure which API method to use edit **package.json**. 14 | 15 | * Set the **APIMethod** to 'stub' to use these express stub routes. 16 | 17 | * Set the method to 'proxy' and define the **proxyURL** to pass all API requests to the proxy URL. 18 | 19 | Default Example 20 | ---------------- 21 | 22 | 1. Create the following models: 23 | 24 | app/models/post.js 25 | 26 | ``` 27 | var attr = DS.attr, 28 | hasMany = DS.hasMany, 29 | belongsTo = DS.belongsTo; 30 | 31 | var Post = DS.Model.extend({ 32 | title: attr(), 33 | comments: hasMany('comment'), 34 | user: attr(), 35 | }); 36 | 37 | export default Post; 38 | ``` 39 | 40 | app/models/comment.js 41 | 42 | ``` 43 | var attr = DS.attr, 44 | hasMany = DS.hasMany, 45 | belongsTo = DS.belongsTo; 46 | 47 | var Comment = DS.Model.extend({ 48 | body: attr() 49 | }); 50 | 51 | export default Comment; 52 | ``` 53 | 54 | 2. Setup the REST adapter for the application: 55 | 56 | app/adapters/application.js 57 | 58 | ``` 59 | var ApplicationAdapter = DS.RESTAdapter.extend({ 60 | namespace: 'api' 61 | }); 62 | 63 | export default ApplicationAdapter; 64 | ``` 65 | 66 | 3. Tell the Index router to query for a post: 67 | 68 | app/routes/index.js 69 | 70 | ``` 71 | var IndexRoute = Ember.Route.extend({ 72 | model: function() { 73 | return this.store.find('post', 1); 74 | } 75 | }); 76 | 77 | export default IndexRoute; 78 | ``` 79 | 80 | 81 | 4. Expose the model properties in the index.hbs template 82 | 83 | app/templates/index.hbs 84 | 85 | ``` 86 |

{{title}}

87 |

{{body}}

88 |
89 |
    90 | {{#each comment in comments}} 91 |
  • 92 |
    {{comment.body}}
    93 |
  • 94 | {{/each}} 95 |
96 |
97 | ``` 98 | 99 | When Ember Data queries the store for the post, it will make an API call to 100 | http://localhost:8000/api/posts/1, to which the express server will respond with 101 | some mock data: 102 | 103 | ``` 104 | { 105 | "post": { 106 | "id": 1, 107 | "title": "Rails is omakase", 108 | "comments": ["1", "2"], 109 | "user" : "dhh" 110 | }, 111 | 112 | "comments": [{ 113 | "id": "1", 114 | "body": "Rails is unagi" 115 | }, { 116 | "id": "2", 117 | "body": "Omakase O_o" 118 | }] 119 | } 120 | ``` -------------------------------------------------------------------------------- /app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Lagerfeuer 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 87 | 88 | 89 | 90 | 91 | 98 | 99 | 100 |
101 |
102 | 103 | 104 | 105 | 106 | 107 | 108 | 111 | 112 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /tasks/express-server.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | var express = require('express'), 3 | lockFile = require('lockfile'), 4 | Helpers = require('./helpers'), 5 | fs = require('fs'), 6 | path = require('path'), 7 | request = require('request'); 8 | 9 | /** 10 | Task for serving the static files. 11 | 12 | Note: The expressServer:debug task looks for files in multiple directories. 13 | */ 14 | grunt.registerTask('expressServer', function(target, proxyMethodToUse) { 15 | // Load namespace module before creating the server 16 | require('express-namespace'); 17 | 18 | var app = express(), 19 | done = this.async(), 20 | proxyMethod = proxyMethodToUse || grunt.config('express-server.options.APIMethod'); 21 | 22 | app.use(lock); 23 | app.use(express.compress()); 24 | 25 | if (proxyMethod === 'stub') { 26 | grunt.log.writeln('Using API Stub'); 27 | 28 | // Load API stub routes 29 | app.use(express.json()); 30 | app.use(express.urlencoded()); 31 | require('../api-stub/routes')(app); 32 | } else if (proxyMethod === 'proxy') { 33 | var proxyURL = grunt.config('express-server.options.proxyURL'); 34 | grunt.log.writeln('Proxying API requests to: ' + proxyURL); 35 | 36 | // Use API proxy 37 | app.all('/api/*', passThrough(proxyURL)); 38 | } 39 | 40 | if (target === 'debug') { 41 | // For `expressServer:debug` 42 | 43 | // Add livereload middlware after lock middleware if enabled 44 | if (Helpers.isPackageAvailable("connect-livereload")) { 45 | app.use(require("connect-livereload")()); 46 | } 47 | 48 | // These three lines simulate what the `copy:assemble` task does 49 | app.use(static({ urlRoot: '/config', directory: 'config' })); 50 | app.use(static({ urlRoot: '/vendor', directory: 'vendor' })); 51 | app.use(static({ directory: 'public' })); 52 | app.use(static({ urlRoot: '/tests', directory: 'tests' })); // For test_helper.js and test_loader.js 53 | 54 | app.use(static({ directory: 'tmp/result' })); 55 | app.use(static({ file: 'tmp/result/index.html' })); // Gotta catch 'em all 56 | } else { 57 | // For `expressServer:dist` 58 | 59 | app.use(lock); 60 | app.use(static({ directory: 'dist' })); 61 | app.use(static({ file: 'dist/index.html' })); // Gotta catch 'em all 62 | } 63 | 64 | var port = parseInt(process.env.PORT || 8000, 10); 65 | if (isNaN(port) || port < 1 || port > 65535) { 66 | grunt.fail.fatal('The PORT environment variable of ' + process.env.PORT + ' is not valid.'); 67 | } 68 | app.listen(port); 69 | grunt.log.ok('Started development server on port %d.', port); 70 | if (!this.flags.keepalive) { done(); } 71 | }); 72 | 73 | 74 | // Middleware 75 | // ========== 76 | 77 | function lock(req, res, next) { // Works with tasks/locking.js 78 | (function retry() { 79 | if (lockFile.checkSync('tmp/connect.lock')) { 80 | setTimeout(retry, 30); 81 | } else { next(); } 82 | })(); 83 | } 84 | 85 | function static(options) { 86 | return function(req, res, next) { // Gotta catch 'em all (and serve index.html) 87 | var filePath = ""; 88 | if (options.directory) { 89 | var regex = new RegExp('^' + (options.urlRoot || '')); 90 | // URL must begin with urlRoot's value 91 | if (!req.path.match(regex)) { next(); return; } 92 | filePath = options.directory + req.path.replace(regex, ''); 93 | } else if (options.file) { 94 | filePath = options.file; 95 | } else { throw new Error('static() isn\'t properly configured!'); } 96 | 97 | fs.stat(filePath, function(err, stats) { 98 | if (err) { next(); return; } // Not a file, not a folder => can't handle it 99 | 100 | // Is it a directory? If so, search for an index.html in it. 101 | if (stats.isDirectory()) { filePath = path.join(filePath, 'index.html'); } 102 | 103 | // Serve the file 104 | res.sendfile(filePath, function(err) { 105 | if (err) { next(); return; } 106 | grunt.verbose.ok('Served: ' + filePath); 107 | }); 108 | }); 109 | }; 110 | } 111 | 112 | function passThrough(target) { 113 | return function(req, res) { 114 | req.pipe(request(target+req.url)).pipe(res); 115 | }; 116 | } 117 | }; 118 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | // To support Coffeescript, SASS, LESS and others, just install 3 | // the appropriate grunt package and it will be automatically included 4 | // in the build process: 5 | // 6 | // * for Coffeescript, run `npm install --save-dev grunt-contrib-coffee` 7 | // 8 | // * for SCSS (without SASS), run `npm install --save-dev grunt-sass` 9 | // * for SCSS/SASS support (may be slower), run 10 | // `npm install --save-dev grunt-contrib-sass` 11 | // This depends on the ruby sass gem, which can be installed with 12 | // `gem install sass` 13 | // * for Compass, run `npm install --save-dev grunt-contrib-compass` 14 | // This depends on the ruby compass gem, which can be installed with 15 | // `gem install compass` 16 | // You should not install SASS if you have installed Compass. 17 | // 18 | // * for LESS, run `npm install --save-dev grunt-contrib-less` 19 | // 20 | // * for Stylus/Nib, `npm install --save-dev grunt-contrib-stylus` 21 | // 22 | // * for Emblem, run the following commands: 23 | // `npm uninstall --save-dev grunt-ember-templates` 24 | // `npm install --save-dev grunt-emblem` 25 | // `bower install emblem.js --save` 26 | // 27 | // * For EmberScript, run `npm install --save-dev grunt-ember-script` 28 | // 29 | // * for LiveReload, `npm install --save-dev connect-livereload` 30 | // 31 | // * for displaying the execution time of the grunt tasks, 32 | // `npm install --save-dev time-grunt` 33 | // 34 | // * for minimizing the index.html at the end of the dist task 35 | // `npm install --save-dev grunt-contrib-htmlmin` 36 | // 37 | // * for minimizing images in the dist task 38 | // `npm install --save-dev grunt-contrib-imagemin` 39 | // 40 | // * for using images based css sprites 41 | // `npm install --save-dev grunt-fancy-sprites` 42 | // `bower install --save fancy-sprites-scss` 43 | // 44 | 45 | var Helpers = require('./tasks/helpers'), 46 | filterAvailable = Helpers.filterAvailableTasks, 47 | _ = grunt.util._, 48 | path = require('path'); 49 | 50 | Helpers.pkg = require("./package.json"); 51 | 52 | if (Helpers.isPackageAvailable("time-grunt")) { 53 | require("time-grunt")(grunt); 54 | } 55 | 56 | // Loads task options from `tasks/options/` 57 | // and loads tasks defined in `package.json` 58 | var config = require('load-grunt-config')(grunt, { 59 | defaultPath: path.join(__dirname, 'tasks/options'), 60 | configPath: path.join(__dirname, 'tasks/custom'), 61 | init: false 62 | }); 63 | grunt.loadTasks('tasks'); // Loads tasks in `tasks/` folder 64 | 65 | config.env = process.env; 66 | 67 | 68 | 69 | 70 | // App Kit's Main Tasks 71 | // ==================== 72 | 73 | 74 | // Generate the production version 75 | // ------------------ 76 | grunt.registerTask('dist', "Build a minified & production-ready version of your app.", [ 77 | 'clean:dist', 78 | 'build:dist', 79 | 'copy:assemble', 80 | 'createDistVersion' 81 | ]); 82 | 83 | 84 | // Default Task 85 | // ------------------ 86 | grunt.registerTask('default', "Build (in debug mode) & test your application.", ['test']); 87 | 88 | 89 | // Servers 90 | // ------------------- 91 | grunt.registerTask('server', "Run your server in development mode, auto-rebuilding when files change.", function(proxyMethod) { 92 | var expressServerTask = 'expressServer:debug'; 93 | if (proxyMethod) { 94 | expressServerTask += ':' + proxyMethod; 95 | } 96 | 97 | grunt.task.run(['clean:debug', 98 | 'build:debug', 99 | expressServerTask, 100 | 'watch' 101 | ]); 102 | }); 103 | 104 | grunt.registerTask('server:dist', "Build and preview a minified & production-ready version of your app.", [ 105 | 'dist', 106 | 'expressServer:dist:keepalive' 107 | ]); 108 | 109 | 110 | // Testing 111 | // ------- 112 | grunt.registerTask('test', "Run your apps's tests once. Uses Google Chrome by default.", [ 113 | 'clean:debug', 'build:debug', 'testem:ci:basic' ]); 114 | 115 | grunt.registerTask('test:ci', "Run your app's tests in PhantomJS. For use in continuous integration (i.e. Travis CI).", [ 116 | 'clean:debug', 'build:debug', 'testem:ci:basic' ]); 117 | 118 | grunt.registerTask('test:browsers', "Run your app's tests in multiple browsers (see tasks/options/testem.js for configuration).", [ 119 | 'clean:debug', 'build:debug', 'testem:ci:browsers' ]); 120 | 121 | grunt.registerTask('test:server', "Start a Testem test server and the standard development server.", [ 122 | 'clean:debug', 123 | 'build:debug', 124 | 'testem:run:basic', 125 | 'expressServer:debug', 126 | 'watch' 127 | ]); 128 | 129 | // Worker tasks 130 | // ================================= 131 | 132 | grunt.registerTask('build:dist', filterAvailable([ 133 | 'createResultDirectory', // Create directoy beforehand, fixes race condition 134 | 'fancySprites:create', 135 | 'concurrent:buildDist', // Executed in parallel, see config below 136 | ])); 137 | 138 | grunt.registerTask('build:debug', filterAvailable([ 139 | 'jshint:tooling', 140 | 'createResultDirectory', // Create directoy beforehand, fixes race condition 141 | 'fancySprites:create', 142 | 'concurrent:buildDebug', // Executed in parallel, see config below 143 | ])); 144 | 145 | grunt.registerTask('createDistVersion', filterAvailable([ 146 | 'useminPrepare', // Configures concat, cssmin and uglify 147 | 'concat', // Combines css and javascript files 148 | 149 | 'cssmin', // Minifies css 150 | 'uglify', // Minifies javascript 151 | 'imagemin', // Optimizes image compression 152 | // 'svgmin', 153 | 'copy:dist', // Copies files not covered by concat and imagemin 154 | 155 | 'rev', // Appends 8 char hash value to filenames 156 | 'usemin', // Replaces file references 157 | 'htmlmin:dist' // Removes comments and whitespace 158 | ])); 159 | 160 | // Parallelize most of the build process 161 | _.merge(config, { 162 | concurrent: { 163 | buildDist: [ 164 | "buildTemplates:dist", 165 | "buildScripts", 166 | "buildStyles", 167 | "buildIndexHTML:dist" 168 | ], 169 | buildDebug: [ 170 | "buildTemplates:debug", 171 | "buildScripts", 172 | "buildStyles", 173 | "buildIndexHTML:debug" 174 | ] 175 | } 176 | }); 177 | 178 | // Templates 179 | grunt.registerTask('buildTemplates:dist', filterAvailable([ 180 | 'emblem:compile', 181 | 'emberTemplates:dist' 182 | ])); 183 | 184 | grunt.registerTask('buildTemplates:debug', filterAvailable([ 185 | 'emblem:compile', 186 | 'emberTemplates:debug' 187 | ])); 188 | 189 | // Scripts 190 | grunt.registerTask('buildScripts', filterAvailable([ 191 | 'jshint:app', 192 | 'jshint:tests', 193 | 'coffee', 194 | 'emberscript', 195 | 'copy:javascriptToTmp', 196 | 'transpile', 197 | 'concat_sourcemap' 198 | ])); 199 | 200 | // Styles 201 | grunt.registerTask('buildStyles', filterAvailable([ 202 | 'compass:compile', 203 | 'sass:compile', 204 | 'less:compile', 205 | 'stylus:compile', 206 | 'copy:cssToResult' 207 | // ToDo: Add 'autoprefixer' 208 | ])); 209 | 210 | // Index HTML 211 | grunt.registerTask('buildIndexHTML:dist', [ 212 | 'preprocess:indexHTMLDistApp', 213 | 'preprocess:indexHTMLDistTests' 214 | ]); 215 | 216 | grunt.registerTask('buildIndexHTML:debug', [ 217 | 'preprocess:indexHTMLDebugApp', 218 | 'preprocess:indexHTMLDebugTests' 219 | ]); 220 | 221 | grunt.registerTask('createResultDirectory', function() { 222 | grunt.file.mkdir('tmp/result'); 223 | }); 224 | 225 | grunt.initConfig(config); 226 | }; 227 | -------------------------------------------------------------------------------- /app/styles/_settings.scss: -------------------------------------------------------------------------------- 1 | // 2 | // FOUNDATION SETTINGS 3 | // 4 | 5 | // Uncomment to use rem-calc() in your settings 6 | // @import "foundation/functions"; 7 | 8 | // $experimental: true; 9 | 10 | // The default font-size is set to 100% of the browser style sheet (usually 16px) 11 | // for compatibility with brower-based text zoom or user-set defaults. 12 | 13 | // Since the typical default browser font-size is 16px, that makes the calculation for grid size. 14 | // If you want your base font-size to be different and not have it affect the grid breakpoints, 15 | // set $rem-base to $base-font-size and make sure $base-font-size is a px value. 16 | // $base-font-size: 100%; 17 | 18 | // The $base-line-height is 100% while $base-font-size is 150% 19 | // $base-line-height: 150%; 20 | 21 | // This is the default html and body font-size for the base rem value. 22 | // $rem-base: 16px; 23 | 24 | // We use this to control whether or not CSS classes come through in the gem files. 25 | // $include-html-classes: true; 26 | // $include-print-styles: true; 27 | // $include-html-global-classes: $include-html-classes; 28 | 29 | // Grid 30 | 31 | // $include-html-grid-classes: $include-html-classes; 32 | 33 | // $row-width: rem-calc(1000); 34 | // $column-gutter: rem-calc(30); 35 | // $total-columns: 12; 36 | 37 | // We use these to control various global styles 38 | // $body-bg: #fff; 39 | // $body-font-color: #222; 40 | // $body-font-family: "Helvetica Neue", "Helvetica", Helvetica, Arial, sans-serif; 41 | // $body-font-weight: normal; 42 | // $body-font-style: normal; 43 | 44 | // We use this to control font-smoothing 45 | // $font-smoothing: antialiased; 46 | 47 | // We use these to control text direction settings 48 | // $text-direction: ltr; 49 | // $opposite-direction: right; 50 | // $default-float: left; 51 | 52 | // We use these as default colors throughout 53 | // $primary-color: #008CBA; 54 | // $secondary-color: #e7e7e7; 55 | // $alert-color: #f04124; 56 | // $success-color: #43AC6A; 57 | // $warning-color: #f08a24; 58 | // $info-color: #a0d3e8; 59 | 60 | // We use these to make sure border radius matches unless we want it different. 61 | // $global-radius: 3px; 62 | // $global-rounded: 1000px; 63 | 64 | // We use these to control inset shadow shiny edges and depressions. 65 | // $shiny-edge-size: 0 1px 0; 66 | // $shiny-edge-color: rgba(#fff, .5); 67 | // $shiny-edge-active-color: rgba(#000, .2); 68 | 69 | // Media Query Ranges 70 | // $small-range: (0em, 40em); 71 | // $medium-range: (40.063em, 64em); 72 | // $large-range: (64.063em, 90em); 73 | // $xlarge-range: (90.063em, 120em); 74 | // $xxlarge-range: (120.063em); 75 | 76 | // $screen: "only screen"; 77 | 78 | // $landscape: "#{$screen} and (orientation: landscape)"; 79 | // $portrait: "#{$screen} and (orientation: portrait)"; 80 | 81 | // $small-up: $screen; 82 | // $small-only: "#{$screen} and (max-width: #{upper-bound($small-range)})"; 83 | 84 | // $medium-up: "#{$screen} and (min-width:#{lower-bound($medium-range)})"; 85 | // $medium-only: "#{$screen} and (min-width:#{lower-bound($medium-range)}) and (max-width:#{upper-bound($medium-range)})"; 86 | 87 | // $large-up: "#{$screen} and (min-width:#{lower-bound($large-range)})"; 88 | // $large-only: "#{$screen} and (min-width:#{lower-bound($large-range)}) and (max-width:#{upper-bound($large-range)})"; 89 | 90 | // $xlarge-up: "#{$screen} and (min-width:#{lower-bound($xlarge-range)})"; 91 | // $xlarge-only: "#{$screen} and (min-width:#{lower-bound($xlarge-range)}) and (max-width:#{upper-bound($xlarge-range)})"; 92 | 93 | // $xxlarge-up: "#{$screen} and (min-width:#{lower-bound($xxlarge-range)})"; 94 | // $xxlarge-only: "#{$screen} and (min-width:#{lower-bound($xxlarge-range)}) and (max-width:#{upper-bound($xxlarge-range)})"; 95 | 96 | // Legacy 97 | // $small: $medium-up; 98 | // $medium: $medium-up; 99 | // $large: $large-up; 100 | 101 | //We use this as cursors values for enabling the option of having custom cursors in the whole site's stylesheet 102 | // $cursor-crosshair-value: crosshair; 103 | // $cursor-default-value: default; 104 | // $cursor-pointer-value: pointer; 105 | // $cursor-help-value: help; 106 | // $cursor-text-value: text; 107 | 108 | // Accordion 109 | 110 | // $include-html-accordion-classes: $include-html-classes; 111 | 112 | // $accordion-navigation-padding: rem-calc(16); 113 | // $accordion-navigation-bg-color: #efefef ; 114 | // $accordion-navigation-hover-bg-color: darken($accordion-navigation-bg-color, 5%); 115 | // $accordion-navigation-active-bg-color: darken($accordion-navigation-bg-color, 3%); 116 | // $accordion-navigation-font-color: #222; 117 | // $accordion-navigation-font-size: rem-calc(16); 118 | // $accordion-navigation-font-family: $body-font-family; 119 | 120 | // $accordion-content-padding: $column-gutter/2; 121 | // $accordion-content-active-bg-color: #fff; 122 | 123 | // Alert Boxes 124 | 125 | // $include-html-alert-classes: $include-html-classes; 126 | 127 | // We use this to control alert padding. 128 | // $alert-padding-top: rem-calc(14); 129 | // $alert-padding-default-float: $alert-padding-top; 130 | // $alert-padding-opposite-direction: $alert-padding-top + rem-calc(10); 131 | // $alert-padding-bottom: $alert-padding-top; 132 | 133 | // We use these to control text style. 134 | // $alert-font-weight: normal; 135 | // $alert-font-size: rem-calc(13); 136 | // $alert-font-color: #fff; 137 | // $alert-font-color-alt: darken($secondary-color, 60%); 138 | 139 | // We use this for close hover effect. 140 | // $alert-function-factor: 5%; 141 | 142 | // We use these to control border styles. 143 | // $alert-border-style: solid; 144 | // $alert-border-width: 1px; 145 | // $alert-border-color: darken($primary-color, $alert-function-factor); 146 | // $alert-bottom-margin: rem-calc(20); 147 | 148 | // We use these to style the close buttons 149 | // $alert-close-color: #333; 150 | // $alert-close-top: 50%; 151 | // $alert-close-position: rem-calc(5); 152 | // $alert-close-font-size: rem-calc(22); 153 | // $alert-close-opacity: 0.3; 154 | // $alert-close-opacity-hover: 0.5; 155 | // $alert-close-padding: 9px 6px 4px; 156 | 157 | // We use this to control border radius 158 | // $alert-radius: $global-radius; 159 | 160 | // Block Grid 161 | 162 | // $include-html-grid-classes: $include-html-classes; 163 | 164 | // We use this to control the maximum number of block grid elements per row 165 | // $block-grid-elements: 12; 166 | // $block-grid-default-spacing: rem-calc(20); 167 | 168 | // Enables media queries for block-grid classes. Set to false if writing semantic HTML. 169 | // $block-grid-media-queries: true; 170 | 171 | // Breadcrumbs 172 | 173 | // $include-html-nav-classes: $include-html-classes; 174 | 175 | // We use this to set the background color for the breadcrumb container. 176 | // $crumb-bg: lighten($secondary-color, 5%); 177 | 178 | // We use these to set the padding around the breadcrumbs. 179 | // $crumb-padding: rem-calc(9 14 9); 180 | // $crumb-side-padding: rem-calc(12); 181 | 182 | // We use these to control border styles. 183 | // $crumb-function-factor: 10%; 184 | // $crumb-border-size: 1px; 185 | // $crumb-border-style: solid; 186 | // $crumb-border-color: darken($crumb-bg, $crumb-function-factor); 187 | // $crumb-radius: $global-radius; 188 | 189 | // We use these to set various text styles for breadcrumbs. 190 | // $crumb-font-size: rem-calc(11); 191 | // $crumb-font-color: $primary-color; 192 | // $crumb-font-color-current: #333; 193 | // $crumb-font-color-unavailable: #999; 194 | // $crumb-font-transform: uppercase; 195 | // $crumb-link-decor: underline; 196 | 197 | // We use these to control the slash between breadcrumbs 198 | // $crumb-slash-color: #aaa; 199 | // $crumb-slash: "/"; 200 | 201 | // Button Groups 202 | 203 | // $include-html-button-classes: $include-html-classes; 204 | 205 | // Sets the margin for the right side by default, and the left margin if right-to-left direction is used 206 | // $button-bar-margin-opposite: rem-calc(10); 207 | // $button-group-border-width: 1px; 208 | 209 | // Clearing 210 | 211 | // $include-html-clearing-classes: $include-html-classes; 212 | 213 | // We use these to set the background colors for parts of Clearing. 214 | // $clearing-bg: #333; 215 | // $clearing-caption-bg: $clearing-bg; 216 | // $clearing-carousel-bg: rgba (51,51,51,0.8); 217 | // $clearing-img-bg: $clearing-bg; 218 | 219 | // We use these to style the close button 220 | // $clearing-close-color: #ccc; 221 | // $clearing-close-size: 30px; 222 | 223 | // We use these to style the arrows 224 | // $clearing-arrow-size: 12px; 225 | // $clearing-arrow-color: $clearing-close-color; 226 | 227 | // We use these to style captions 228 | // $clearing-caption-font-color: #ccc; 229 | // $clearing-caption-font-size: 0.875em; 230 | // $clearing-caption-padding: 10px 30px 20px; 231 | 232 | // We use these to make the image and carousel height and style 233 | // $clearing-active-img-height: 85%; 234 | // $clearing-carousel-height: 120px; 235 | // $clearing-carousel-thumb-width: 120px; 236 | // $clearing-carousel-thumb-active-border: 1px solid rgb(255,255,255); 237 | 238 | // Dropdown 239 | 240 | // $include-html-button-classes: $include-html-classes; 241 | 242 | // We use these to controls height and width styles. 243 | // $f-dropdown-max-width: 200px; 244 | // $f-dropdown-height: auto; 245 | // $f-dropdown-max-height: none; 246 | // $f-dropdown-margin-top: 2px; 247 | 248 | // We use this to control the background color 249 | // $f-dropdown-bg: #fff; 250 | 251 | // We use this to set the border styles for dropdowns. 252 | // $f-dropdown-border-style: solid; 253 | // $f-dropdown-border-width: 1px; 254 | // $f-dropdown-border-color: darken(#fff, 20%); 255 | 256 | // We use these to style the triangle pip. 257 | // $f-dropdown-triangle-size: 6px; 258 | // $f-dropdown-triangle-color: #fff; 259 | // $f-dropdown-triangle-side-offset: 10px; 260 | 261 | // We use these to control styles for the list elements. 262 | // $f-dropdown-list-style: none; 263 | // $f-dropdown-font-color: #555; 264 | // $f-dropdown-font-size: rem-calc(14); 265 | // $f-dropdown-list-padding: rem-calc(5, 10); 266 | // $f-dropdown-line-height: rem-calc(18); 267 | // $f-dropdown-list-hover-bg: #eeeeee ; 268 | // $dropdown-mobile-default-float: 0; 269 | 270 | // We use this to control the styles for when the dropdown has custom content. 271 | // $f-dropdown-content-padding: rem-calc(20); 272 | 273 | // Dropdown Buttons 274 | 275 | // $include-html-button-classes: $include-html-classes; 276 | 277 | // We use these to set the color of the pip in dropdown buttons 278 | // $dropdown-button-pip-color: #fff; 279 | // $dropdown-button-pip-color-alt: #333; 280 | 281 | // $button-pip-tny: rem-calc(6); 282 | // $button-pip-sml: rem-calc(7); 283 | // $button-pip-med: rem-calc(9); 284 | // $button-pip-lrg: rem-calc(11); 285 | 286 | // We use these to style tiny dropdown buttons 287 | // $dropdown-button-padding-tny: $button-pip-tny * 7; 288 | // $dropdown-button-pip-size-tny: $button-pip-tny; 289 | // $dropdown-button-pip-opposite-tny: $button-pip-tny * 3; 290 | // $dropdown-button-pip-top-tny: -$button-pip-tny / 2 + rem-calc(1); 291 | 292 | // We use these to style small dropdown buttons 293 | // $dropdown-button-padding-sml: $button-pip-sml * 7; 294 | // $dropdown-button-pip-size-sml: $button-pip-sml; 295 | // $dropdown-button-pip-opposite-sml: $button-pip-sml * 3; 296 | // $dropdown-button-pip-top-sml: -$button-pip-sml / 2 + rem-calc(1); 297 | 298 | // We use these to style medium dropdown buttons 299 | // $dropdown-button-padding-med: $button-pip-med * 6 + rem-calc(3); 300 | // $dropdown-button-pip-size-med: $button-pip-med - rem-calc(3); 301 | // $dropdown-button-pip-opposite-med: $button-pip-med * 2.5; 302 | // $dropdown-button-pip-top-med: -$button-pip-med / 2 + rem-calc(2); 303 | 304 | // We use these to style large dropdown buttons 305 | // $dropdown-button-padding-lrg: $button-pip-lrg * 5 + rem-calc(3); 306 | // $dropdown-button-pip-size-lrg: $button-pip-lrg - rem-calc(6); 307 | // $dropdown-button-pip-opposite-lrg: $button-pip-lrg * 2.5; 308 | // $dropdown-button-pip-top-lrg: -$button-pip-lrg / 2 + rem-calc(3); 309 | 310 | // Flex Video 311 | 312 | // $include-html-media-classes: $include-html-classes; 313 | 314 | // We use these to control video container padding and margins 315 | // $flex-video-padding-top: rem-calc(25); 316 | // $flex-video-padding-bottom: 67.5%; 317 | // $flex-video-margin-bottom: rem-calc(16); 318 | 319 | // We use this to control widescreen bottom padding 320 | // $flex-video-widescreen-padding-bottom: 57.25%; 321 | 322 | // Forms 323 | 324 | // $include-html-form-classes: $include-html-classes; 325 | 326 | // We use this to set the base for lots of form spacing and positioning styles 327 | // $form-spacing: rem-calc(16); 328 | 329 | // We use these to style the labels in different ways 330 | // $form-label-pointer: pointer; 331 | // $form-label-font-size: rem-calc(14); 332 | // $form-label-font-weight: normal; 333 | // $form-label-font-color: lighten(#000, 30%); 334 | // $form-label-bottom-margin: rem-calc(8); 335 | // $input-font-family: inherit; 336 | // $input-font-color: rgba(0,0,0,0.75); 337 | // $input-font-size: rem-calc(14); 338 | // $input-bg-color: #fff; 339 | // $input-focus-bg-color: darken(#fff, 2%); 340 | // $input-border-color: darken(#fff, 20%); 341 | // $input-focus-border-color: darken(#fff, 40%); 342 | // $input-border-style: solid; 343 | // $input-border-width: 1px; 344 | // $input-disabled-bg: #ddd; 345 | // $input-box-shadow: inset 0 1px 2px rgba(0,0,0,0.1); 346 | // $input-include-glowing-effect: true; 347 | 348 | // We use these to style the fieldset border and spacing. 349 | // $fieldset-border-style: solid; 350 | // $fieldset-border-width: 1px; 351 | // $fieldset-border-color: #ddd; 352 | // $fieldset-padding: rem-calc(20); 353 | // $fieldset-margin: rem-calc(18 0); 354 | 355 | // We use these to style the legends when you use them 356 | // $legend-bg: #fff; 357 | // $legend-font-weight: bold; 358 | // $legend-padding: rem-calc(0 3); 359 | 360 | // We use these to style the prefix and postfix input elements 361 | // $input-prefix-bg: darken(#fff, 5%); 362 | // $input-prefix-border-color: darken(#fff, 20%); 363 | // $input-prefix-border-size: 1px; 364 | // $input-prefix-border-type: solid; 365 | // $input-prefix-overflow: hidden; 366 | // $input-prefix-font-color: #333; 367 | // $input-prefix-font-color-alt: #fff; 368 | 369 | // We use these to style the error states for inputs and labels 370 | // $input-error-message-padding: rem-calc(6 9 9); 371 | // $input-error-message-top: -1px; 372 | // $input-error-message-font-size: rem-calc(12); 373 | // $input-error-message-font-weight: normal; 374 | // $input-error-message-font-style: italic; 375 | // $input-error-message-font-color: #fff; 376 | // $input-error-message-font-color-alt: #333; 377 | 378 | // We use this to style the glowing effect of inputs when focused 379 | // $glowing-effect-fade-time: 0.45s; 380 | // $glowing-effect-color: $input-focus-border-color; 381 | 382 | // Select variables 383 | // $select-bg-color: #fafafa ; 384 | 385 | // Inline Lists 386 | 387 | // $include-html-inline-list-classes: $include-html-classes; 388 | 389 | // We use this to control the margins and padding of the inline list. 390 | // $inline-list-top-margin: 0; 391 | // $inline-list-opposite-margin: 0; 392 | // $inline-list-bottom-margin: rem-calc(17); 393 | // $inline-list-default-float-margin: rem-calc(-22); 394 | 395 | // $inline-list-padding: 0; 396 | 397 | // We use this to control the overflow of the inline list. 398 | // $inline-list-overflow: hidden; 399 | 400 | // We use this to control the list items 401 | // $inline-list-display: block; 402 | 403 | // We use this to control any elments within list items 404 | // $inline-list-children-display: block; 405 | 406 | // Joyride 407 | 408 | // $include-html-joyride-classes: $include-html-classes; 409 | 410 | // Controlling default Joyride styles 411 | // $joyride-tip-bg: #333; 412 | // $joyride-tip-default-width: 300px; 413 | // $joyride-tip-padding: rem-calc(18 20 24); 414 | // $joyride-tip-border: solid 1px #555; 415 | // $joyride-tip-radius: 4px; 416 | // $joyride-tip-position-offset: 22px; 417 | 418 | // Here, we're setting the tip dont styles 419 | // $joyride-tip-font-color: #fff; 420 | // $joyride-tip-font-size: rem-calc(14); 421 | // $joyride-tip-header-weight: bold; 422 | 423 | // This changes the nub size 424 | // $joyride-tip-nub-size: 10px; 425 | 426 | // This adjusts the styles for the timer when its enabled 427 | // $joyride-tip-timer-width: 50px; 428 | // $joyride-tip-timer-height: 3px; 429 | // $joyride-tip-timer-color: #666; 430 | 431 | // This changes up the styles for the close button 432 | // $joyride-tip-close-color: #777; 433 | // $joyride-tip-close-size: 24px; 434 | // $joyride-tip-close-weight: normal; 435 | 436 | // When Joyride is filling the screen, we use this style for the bg 437 | // $joyride-screenfill: rgba(0,0,0,0.5); 438 | 439 | // Keystrokes 440 | 441 | // $include-html-type-classes: $include-html-classes; 442 | 443 | // We use these to control text styles. 444 | // $keystroke-font: "Consolas", "Menlo", "Courier", monospace; 445 | // $keystroke-font-size: rem-calc(14); 446 | // $keystroke-font-color: #222; 447 | // $keystroke-font-color-alt: #fff; 448 | // $keystroke-function-factor: 7%; 449 | 450 | // We use this to control keystroke padding. 451 | // $keystroke-padding: rem-calc(2 4 0); 452 | 453 | // We use these to control background and border styles. 454 | // $keystroke-bg: darken(#fff, $keystroke-function-factor); 455 | // $keystroke-border-style: solid; 456 | // $keystroke-border-width: 1px; 457 | // $keystroke-border-color: darken($keystroke-bg, $keystroke-function-factor); 458 | // $keystroke-radius: $global-radius; 459 | 460 | // Labels 461 | 462 | // $include-html-label-classes: $include-html-classes; 463 | 464 | // We use these to style the labels 465 | // $label-padding: rem-calc(4 8 6); 466 | // $label-radius: $global-radius; 467 | 468 | // We use these to style the label text 469 | // $label-font-sizing: rem-calc(11); 470 | // $label-font-weight: normal; 471 | // $label-font-color: #333; 472 | // $label-font-color-alt: #fff; 473 | // $label-font-family: $body-font-family; 474 | 475 | // Magellan 476 | 477 | // $include-html-magellan-classes: $include-html-classes; 478 | 479 | // $magellan-bg: #fff; 480 | // $magellan-padding: 10px; 481 | 482 | // Off-canvas 483 | 484 | // $tabbar-bg: #333; 485 | // $tabbar-height: rem-calc(45); 486 | // $tabbar-line-height: $tabbar-height; 487 | // $tabbar-color: #FFF; 488 | // $tabbar-middle-padding: 0 rem-calc(10); 489 | 490 | // Off Canvas Divider Styles 491 | // $tabbar-right-section-border: solid 1px lighten($tabbar-bg, 10%); 492 | // $tabbar-left-section-border: solid 1px darken($tabbar-bg, 10%); 493 | 494 | // Off Canvas Tab Bar Headers 495 | // $tabbar-header-color: #FFF; 496 | // $tabbar-header-weight: bold; 497 | // $tabbar-header-line-height: $tabbar-height; 498 | // $tabbar-header-margin: 0; 499 | 500 | // Off Canvas Menu Variables 501 | // $off-canvas-width: 250px; 502 | // $off-canvas-bg: #333; 503 | 504 | // Off Canvas Menu List Variables 505 | // $off-canvas-label-padding: 0.3rem rem-calc(15); 506 | // $off-canvas-label-color: #999; 507 | // $off-canvas-label-text-transform: uppercase; 508 | // $off-canvas-label-font-weight: bold; 509 | // $off-canvas-label-bg: #444; 510 | // $off-canvas-label-border-top: 1px solid lighten(#444, 10%); 511 | // $off-canvas-label-border-bottom: none; 512 | // $off-canvas-label-margin:0; 513 | // $off-canvas-link-padding: rem-calc(10, 15); 514 | // $off-canvas-link-color: rgba(#FFF, 0.7); 515 | // $off-canvas-link-border-bottom: 1px solid darken($off-canvas-bg, 5%); 516 | 517 | // Off Canvas Menu Icon Variables 518 | // $tabbar-menu-icon-color: #FFF; 519 | // $tabbar-menu-icon-hover: darken($tabbar-menu-icon-color, 30%); 520 | 521 | // $tabbar-menu-icon-text-indent: rem-calc(35); 522 | // $tabbar-menu-icon-width: $tabbar-height; 523 | // $tabbar-menu-icon-height: $tabbar-height; 524 | // $tabbar-menu-icon-line-height: rem-calc(33); 525 | // $tabbar-menu-icon-padding: 0; 526 | 527 | // $tabbar-hamburger-icon-width: rem-calc(16); 528 | // $tabbar-hamburger-icon-left: rem-calc(13); 529 | // $tabbar-hamburger-icon-top: rem-calc(5); 530 | 531 | // Off Canvas Back-Link Overlay 532 | // $off-canvas-overlay-transition: background 300ms ease; 533 | // $off-canvas-overlay-cursor: pointer; 534 | // $off-canvas-overlay-box-shadow: -4px 0 4px rgba(#000, 0.5), 4px 0 4px rgba(#000, 0.5); 535 | // $off-canvas-overlay-background: rgba(#FFF, 0.2); 536 | // $off-canvas-overlay-background-hover: rgba(#FFF, 0.05); 537 | 538 | // Transition Variabls 539 | // $menu-slide: "transform 500ms ease"; 540 | 541 | // Orbit 542 | 543 | // $include-html-orbit-classes: $include-html-classes; 544 | 545 | // We use these to control the caption styles 546 | // $orbit-container-bg: none; 547 | // $orbit-caption-bg: rgba(51,51,51, 0.8); 548 | // $orbit-caption-font-color: #fff; 549 | // $orbit-caption-font-size: rem-calc(14); 550 | // $orbit-caption-position: "bottom"; // Supported values: "bottom", "under" 551 | // $orbit-caption-padding: rem-calc(10,14); 552 | // $orbit-caption-height: auto; 553 | 554 | // We use these to control the left/right nav styles 555 | // $orbit-nav-bg: none; 556 | // $orbit-nav-bg-hover: rgba(0,0,0,0.3); 557 | // $orbit-nav-arrow-color: #fff; 558 | // $orbit-nav-arrow-color-hover: #fff; 559 | 560 | // We use these to control the timer styles 561 | // $orbit-timer-bg: rgba(255,255,255,0.3); 562 | // $orbit-timer-show-progress-bar: true; 563 | 564 | // We use these to control the bullet nav styles 565 | // $orbit-bullet-nav-color: #ccc; 566 | // $orbit-bullet-nav-color-active: #999; 567 | // $orbit-bullet-radius: rem-calc(9); 568 | 569 | // We use these to controls the style of slide numbers 570 | // $orbit-slide-number-bg: rgba(0,0,0,0); 571 | // $orbit-slide-number-font-color: #fff; 572 | // $orbit-slide-number-padding: rem-calc(5); 573 | 574 | // Graceful Loading Wrapper and preloader 575 | // $wrapper-class: "slideshow-wrapper"; 576 | // $preloader-class: "preloader"; 577 | 578 | // Pagination 579 | 580 | // $include-html-nav-classes: $include-html-classes; 581 | 582 | // We use these to control the pagination container 583 | // $pagination-height: rem-calc(24); 584 | // $pagination-margin: rem-calc(-5); 585 | 586 | // We use these to set the list-item properties 587 | // $pagination-li-float: $default-float; 588 | // $pagination-li-height: rem-calc(24); 589 | // $pagination-li-font-color: #222; 590 | // $pagination-li-font-size: rem-calc(14); 591 | // $pagination-li-margin: rem-calc(5); 592 | 593 | // We use these for the pagination anchor links 594 | // $pagination-link-pad: rem-calc(1 10 1); 595 | // $pagination-link-font-color: #999; 596 | // $pagination-link-active-bg: darken(#fff, 10%); 597 | 598 | // We use these for disabled anchor links 599 | // $pagination-link-unavailable-cursor: default; 600 | // $pagination-link-unavailable-font-color: #999; 601 | // $pagination-link-unavailable-bg-active: transparent; 602 | 603 | // We use these for currently selected anchor links 604 | // $pagination-link-current-background: $primary-color; 605 | // $pagination-link-current-font-color: #fff; 606 | // $pagination-link-current-font-weight: bold; 607 | // $pagination-link-current-cursor: default; 608 | // $pagination-link-current-active-bg: $primary-color; 609 | 610 | // Panels 611 | 612 | // $include-html-panel-classes: $include-html-classes; 613 | 614 | // We use these to control the background and border styles 615 | // $panel-bg: darken(#fff, 5%); 616 | // $panel-border-style: solid; 617 | // $panel-border-size: 1px; 618 | 619 | // We use this % to control how much we darken things on hover 620 | // $panel-function-factor: 10%; 621 | // $panel-border-color: darken($panel-bg, $panel-function-factor); 622 | 623 | // We use these to set default inner padding and bottom margin 624 | // $panel-margin-bottom: rem-calc(20); 625 | // $panel-padding: rem-calc(20); 626 | 627 | // We use these to set default font colors 628 | // $panel-font-color: #333; 629 | // $panel-font-color-alt: #fff; 630 | 631 | // $panel-header-adjust: true; 632 | // $callout-panel-link-color: $primary-color; 633 | 634 | // Pricing Tables 635 | 636 | // $include-html-pricing-classes: $include-html-classes; 637 | 638 | // We use this to control the border color 639 | // $price-table-border: solid 1px #ddd; 640 | 641 | // We use this to control the bottom margin of the pricing table 642 | // $price-table-margin-bottom: rem-calc(20); 643 | 644 | // We use these to control the title styles 645 | // $price-title-bg: #333; 646 | // $price-title-padding: rem-calc(15 20); 647 | // $price-title-align: center; 648 | // $price-title-color: #eee; 649 | // $price-title-weight: normal; 650 | // $price-title-size: rem-calc(16); 651 | // $price-title-font-family: $body-font-family; 652 | 653 | // We use these to control the price styles 654 | // $price-money-bg: #f6f6f6 ; 655 | // $price-money-padding: rem-calc(15 20); 656 | // $price-money-align: center; 657 | // $price-money-color: #333; 658 | // $price-money-weight: normal; 659 | // $price-money-size: rem-calc(32); 660 | // $price-money-font-family: $body-font-family; 661 | 662 | 663 | // We use these to control the description styles 664 | // $price-bg: #fff; 665 | // $price-desc-color: #777; 666 | // $price-desc-padding: rem-calc(15); 667 | // $price-desc-align: center; 668 | // $price-desc-font-size: rem-calc(12); 669 | // $price-desc-weight: normal; 670 | // $price-desc-line-height: 1.4; 671 | // $price-desc-bottom-border: dotted 1px #ddd; 672 | 673 | // We use these to control the list item styles 674 | // $price-item-color: #333; 675 | // $price-item-padding: rem-calc(15); 676 | // $price-item-align: center; 677 | // $price-item-font-size: rem-calc(14); 678 | // $price-item-weight: normal; 679 | // $price-item-bottom-border: dotted 1px #ddd; 680 | 681 | // We use these to control the CTA area styles 682 | // $price-cta-bg: #fff; 683 | // $price-cta-align: center; 684 | // $price-cta-padding: rem-calc(20 20 0); 685 | 686 | // Progress Meters 687 | 688 | // $include-html-media-classes: $include-html-classes; 689 | 690 | // We use this to se the prog bar height 691 | // $progress-bar-height: rem-calc(25); 692 | // $progress-bar-color: #f6f6f6 ; 693 | 694 | // We use these to control the border styles 695 | // $progress-bar-border-color: darken(#fff, 20%); 696 | // $progress-bar-border-size: 1px; 697 | // $progress-bar-border-style: solid; 698 | // $progress-bar-border-radius: $global-radius; 699 | 700 | // We use these to control the margin & padding 701 | // $progress-bar-pad: rem-calc(2); 702 | // $progress-bar-margin-bottom: rem-calc(10); 703 | 704 | // We use these to set the meter colors 705 | // $progress-meter-color: $primary-color; 706 | // $progress-meter-secondary-color: $secondary-color; 707 | // $progress-meter-success-color: $success-color; 708 | // $progress-meter-alert-color: $alert-color; 709 | 710 | // Reveal 711 | 712 | // $include-html-reveal-classes: $include-html-classes; 713 | 714 | // We use these to control the style of the reveal overlay. 715 | // $reveal-overlay-bg: rgba(#000, .45); 716 | // $reveal-overlay-bg-old: #000; 717 | 718 | // We use these to control the style of the modal itself. 719 | // $reveal-modal-bg: #fff; 720 | // $reveal-position-top: 50px; 721 | // $reveal-default-width: 80%; 722 | // $reveal-modal-padding: rem-calc(20); 723 | // $reveal-box-shadow: 0 0 10px rgba(#000,.4); 724 | 725 | // We use these to style the reveal close button 726 | // $reveal-close-font-size: rem-calc(22); 727 | // $reveal-close-top: rem-calc(8); 728 | // $reveal-close-side: rem-calc(11); 729 | // $reveal-close-color: #aaa; 730 | // $reveal-close-weight: bold; 731 | 732 | // We use these to control the modal border 733 | // $reveal-border-style: solid; 734 | // $reveal-border-width: 1px; 735 | // $reveal-border-color: #666; 736 | 737 | // $reveal-modal-class: "reveal-modal"; 738 | // $close-reveal-modal-class: "close-reveal-modal"; 739 | 740 | // Side Nav 741 | 742 | // $include-html-nav-classes: $include-html-classes; 743 | 744 | // We use this to control padding. 745 | // $side-nav-padding: rem-calc(14 0); 746 | 747 | // We use these to control list styles. 748 | // $side-nav-list-type: none; 749 | // $side-nav-list-position: inside; 750 | // $side-nav-list-margin: rem-calc(0 0 7 0); 751 | 752 | // We use these to control link styles. 753 | // $side-nav-link-color: $primary-color; 754 | // $side-nav-link-color-active: lighten(#000, 30%); 755 | // $side-nav-font-size: rem-calc(14); 756 | // $side-nav-font-weight: normal; 757 | // $side-nav-font-family: $body-font-family; 758 | // $side-nav-active-font-family: $side-nav-font-family; 759 | 760 | 761 | 762 | // We use these to control border styles 763 | // $side-nav-divider-size: 1px; 764 | // $side-nav-divider-style: solid; 765 | // $side-nav-divider-color: darken(#fff, 10%); 766 | 767 | // Split Buttons 768 | 769 | // $include-html-button-classes: $include-html-classes; 770 | 771 | // We use these to control different shared styles for Split Buttons 772 | // $split-button-function-factor: 10%; 773 | // $split-button-pip-color: #fff; 774 | // $split-button-pip-color-alt: #333; 775 | // $split-button-active-bg-tint: rgba(0,0,0,0.1); 776 | 777 | // We use these to control tiny split buttons 778 | // $split-button-padding-tny: $button-pip-tny * 10; 779 | // $split-button-span-width-tny: $button-pip-tny * 6; 780 | // $split-button-pip-size-tny: $button-pip-tny; 781 | // $split-button-pip-top-tny: $button-pip-tny * 2; 782 | // $split-button-pip-default-float-tny: rem-calc(-6); 783 | 784 | // We use these to control small split buttons 785 | // $split-button-padding-sml: $button-pip-sml * 10; 786 | // $split-button-span-width-sml: $button-pip-sml * 6; 787 | // $split-button-pip-size-sml: $button-pip-sml; 788 | // $split-button-pip-top-sml: $button-pip-sml * 1.5; 789 | // $split-button-pip-default-float-sml: rem-calc(-6); 790 | 791 | // We use these to control medium split buttons 792 | // $split-button-padding-med: $button-pip-med * 9; 793 | // $split-button-span-width-med: $button-pip-med * 5.5; 794 | // $split-button-pip-size-med: $button-pip-med - rem-calc(3); 795 | // $split-button-pip-top-med: $button-pip-med * 1.5; 796 | // $split-button-pip-default-float-med: rem-calc(-6); 797 | 798 | // We use these to control large split buttons 799 | // $split-button-padding-lrg: $button-pip-lrg * 8; 800 | // $split-button-span-width-lrg: $button-pip-lrg * 5; 801 | // $split-button-pip-size-lrg: $button-pip-lrg - rem-calc(6); 802 | // $split-button-pip-top-lrg: $button-pip-lrg + rem-calc(5); 803 | // $split-button-pip-default-float-lrg: rem-calc(-6); 804 | 805 | // Sub Nav 806 | 807 | // $include-html-nav-classes: $include-html-classes; 808 | 809 | // We use these to control margin and padding 810 | // $sub-nav-list-margin: rem-calc(-4 0 18); 811 | // $sub-nav-list-padding-top: rem-calc(4); 812 | 813 | // We use this to control the definition 814 | // $sub-nav-font-family: $body-font-family; 815 | // $sub-nav-font-size: rem-calc(14); 816 | // $sub-nav-font-color: #999; 817 | // $sub-nav-font-weight: normal; 818 | // $sub-nav-text-decoration: none; 819 | // $sub-nav-border-radius: 3px; 820 | // $sub-nav-font-color-hover: darken($sub-nav-font-color, 15%); 821 | 822 | 823 | // We use these to control the active item styles 824 | 825 | // $sub-nav-active-font-weight: normal; 826 | // $sub-nav-active-bg: $primary-color; 827 | // $sub-nav-active-bg-hover: darken($sub-nav-active-bg, 5%); 828 | // $sub-nav-active-color: #fff; 829 | // $sub-nav-active-padding: rem-calc(3 16); 830 | // $sub-nav-active-cursor: default; 831 | 832 | // $sub-nav-item-divider: ""; 833 | // $sub-nav-item-divider-margin: rem-calc(12); 834 | 835 | // Tables 836 | 837 | // $include-html-table-classes: $include-html-classes; 838 | 839 | // These control the background color for the table and even rows 840 | // $table-bg: #fff; 841 | // $table-even-row-bg: #f9f9f9 ; 842 | 843 | // These control the table cell border style 844 | // $table-border-style: solid; 845 | // $table-border-size: 1px; 846 | // $table-border-color: #ddd; 847 | 848 | // These control the table head styles 849 | // $table-head-bg: #f5f5f5 ; 850 | // $table-head-font-size: rem-calc(14); 851 | // $table-head-font-color: #222; 852 | // $table-head-font-weight: bold; 853 | // $table-head-padding: rem-calc(8 10 10); 854 | 855 | // These control the row padding and font styles 856 | // $table-row-padding: rem-calc(9 10); 857 | // $table-row-font-size: rem-calc(14); 858 | // $table-row-font-color: #222; 859 | // $table-line-height: rem-calc(18); 860 | 861 | // These are for controlling the display and margin of tables 862 | // $table-display: table-cell; 863 | // $table-margin-bottom: rem-calc(20); 864 | 865 | // 866 | // TABS 867 | // 868 | 869 | // $include-html-tabs-classes: $include-html-classes; 870 | 871 | // $tabs-navigation-padding: rem-calc(16); 872 | // $tabs-navigation-bg-color: #efefef ; 873 | // $tabs-navigation-hover-bg-color: darken($tabs-navigation-bg-color, 5%); 874 | // $tabs-navigation-font-color: #222; 875 | // $tabs-navigation-font-size: rem-calc(16); 876 | // $tabs-navigation-font-family: $body-font-family; 877 | 878 | // $tabs-content-margin-bottom: rem-calc(24); 879 | // $tabs-content-padding: $column-gutter/2; 880 | 881 | // $tabs-vertical-navigation-margin-bottom: 1.25rem; 882 | 883 | // 884 | // THUMBNAILS 885 | // 886 | 887 | // $include-html-media-classes: $include-html-classes; 888 | 889 | // We use these to control border styles 890 | // $thumb-border-style: solid; 891 | // $thumb-border-width: 4px; 892 | // $thumb-border-color: #fff; 893 | // $thumb-box-shadow: 0 0 0 1px rgba(#000,.2); 894 | // $thumb-box-shadow-hover: 0 0 6px 1px rgba($primary-color,0.5); 895 | 896 | // Radius and transition speed for thumbs 897 | // $thumb-radius: $global-radius; 898 | // $thumb-transition-speed: 200ms; 899 | 900 | // 901 | // TOOLTIPS 902 | // 903 | 904 | // $include-html-tooltip-classes: $include-html-classes; 905 | 906 | // $has-tip-border-bottom: dotted 1px #ccc; 907 | // $has-tip-font-weight: bold; 908 | // $has-tip-font-color: #333; 909 | // $has-tip-border-bottom-hover: dotted 1px darken($primary-color, 20%); 910 | // $has-tip-font-color-hover: $primary-color; 911 | // $has-tip-cursor-type: help; 912 | 913 | // $tooltip-padding: rem-calc(12); 914 | // $tooltip-bg: #333; 915 | // $tooltip-font-size: rem-calc(14); 916 | // $tooltip-font-weight: normal; 917 | // $tooltip-font-color: #fff; 918 | // $tooltip-line-height: 1.3; 919 | // $tooltip-close-font-size: rem-calc(10); 920 | // $tooltip-close-font-weight: normal; 921 | // $tooltip-close-font-color: #777; 922 | // $tooltip-font-size-sml: rem-calc(14); 923 | // $tooltip-radius: $global-radius; 924 | // $tooltip-pip-size: 5px; 925 | 926 | // 927 | // TOP BAR 928 | // 929 | 930 | // $include-html-top-bar-classes: $include-html-classes; 931 | 932 | // Background color for the top bar 933 | // $topbar-bg-color: #333; 934 | // $topbar-bg: $topbar-bg-color; 935 | 936 | // Height and margin 937 | // $topbar-height: 45px; 938 | // $topbar-margin-bottom: 0; 939 | 940 | // Control Input height for top bar 941 | 942 | // Controlling the styles for the title in the top bar 943 | // $topbar-title-weight: normal; 944 | // $topbar-title-font-size: rem-calc(17); 945 | 946 | // Style the top bar dropdown elements 947 | // $topbar-dropdown-bg: #333; 948 | // $topbar-dropdown-link-color: #fff; 949 | // $topbar-dropdown-link-bg: #333; 950 | // $topbar-dropdown-toggle-size: 5px; 951 | // $topbar-dropdown-toggle-color: #fff; 952 | // $topbar-dropdown-toggle-alpha: 0.4; 953 | 954 | // Set the link colors and styles for top-level nav 955 | // $topbar-link-color: #fff; 956 | // $topbar-link-color-hover: #fff; 957 | // $topbar-link-color-active: #fff; 958 | // $topbar-link-weight: normal; 959 | // $topbar-link-font-size: rem-calc(13); 960 | // $topbar-link-hover-lightness: -10%; // Darken by 10% 961 | // $topbar-link-bg-hover: #272727 ; 962 | // $topbar-link-bg-active: $primary-color; 963 | // $topbar-link-bg-active-hover: darken($primary-color, 5%); 964 | // $topbar-link-font-family: $body-font-family; 965 | 966 | // $topbar-button-font-size: 0.75rem; 967 | 968 | // $topbar-dropdown-label-color: #777; 969 | // $topbar-dropdown-label-text-transform: uppercase; 970 | // $topbar-dropdown-label-font-weight: bold; 971 | // $topbar-dropdown-label-font-size: rem-calc(10); 972 | // $topbar-dropdown-label-bg: #333; 973 | 974 | // Top menu icon styles 975 | // $topbar-menu-link-transform: uppercase; 976 | // $topbar-menu-link-font-size: rem-calc(13); 977 | // $topbar-menu-link-weight: bold; 978 | // $topbar-menu-link-color: #fff; 979 | // $topbar-menu-icon-color: #fff; 980 | // $topbar-menu-link-color-toggled: #888; 981 | // $topbar-menu-icon-color-toggled: #888; 982 | 983 | // Transitions and breakpoint styles 984 | // $topbar-transition-speed: 300ms; 985 | // Using rem-calc for the below breakpoint causes issues with top bar 986 | // $topbar-breakpoint: #{upper-bound($medium-range)}; // Change to 9999px for always mobile layout 987 | // $topbar-media-query: "only screen and (min-width: #{upper-bound($medium-range)})"; 988 | 989 | // Divider Styles 990 | // $topbar-divider-border-bottom: solid 1px lighten($topbar-bg-color, 10%); 991 | // $topbar-divider-border-top: solid 1px darken($topbar-bg-color, 10%); 992 | 993 | // Sticky Class 994 | // $topbar-sticky-class: ".sticky"; 995 | // $topbar-arrows: true; //Set false to remove the triangle icon from the menu item 996 | --------------------------------------------------------------------------------