diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..beffa30 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,11 @@ +root = true + +[*] +indent_style = space +indent_size = 2 +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false diff --git a/.gitignore b/.gitignore index 331742c..d55c6a1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,10 @@ .DS_Store *.sublime-project *.sublime-workspace +.idea/* +.vscode +node_modules dump -settings.json -.idea/* \ No newline at end of file +settings-development.json +settings-production.json +npm-debug.log diff --git a/.meteor/.finished-upgraders b/.meteor/.finished-upgraders index 61ee313..aa60704 100755 --- a/.meteor/.finished-upgraders +++ b/.meteor/.finished-upgraders @@ -10,3 +10,6 @@ notices-for-facebook-graph-api-2 1.2.0-meteor-platform-split 1.2.0-cordova-changes 1.2.0-breaking-changes +1.3.0-split-minifiers-package +1.4.0-remove-old-dev-bundle-link +1.4.1-add-shell-server-package diff --git a/.meteor/.id b/.meteor/.id index 3265646..a3bba18 100644 --- a/.meteor/.id +++ b/.meteor/.id @@ -4,4 +4,4 @@ # - ensuring you don't accidentally deploy one app on top of another # - providing package authors with aggregated statistics -17x7iw3cla1ql97roxh +15l9ihseylimk15ohbaz diff --git a/.meteor/packages b/.meteor/packages index 7de177b..9ebbcd6 100755 --- a/.meteor/packages +++ b/.meteor/packages @@ -1,28 +1,28 @@ # Meteor packages used by this project, one per line. +# Check this file (and the other files in this directory) into your repository. # # 'meteor add' and 'meteor remove' will edit this file for you, # but you can also edit it by hand. -# Meteor core +meteor-base@1.0.4 # Packages every Meteor app needs to have +mobile-experience@1.0.4 # Packages for a great mobile UX +mongo@1.1.14 # The database Meteor supports right now +blaze-html-templates@1.0.4 # Compile .html files into Meteor Blaze views +reactive-var@1.0.11 # Reactive variable for tracker +jquery@1.11.10 # Helpful client-side library +tracker@1.1.1 # Meteor's client-side reactive programming library -standard-minifiers -meteor-base -mobile-experience -mongo -blaze-html-templates -session -jquery -tracker -logging -reload -random -ejson -spacebars -check -accounts-base +standard-minifier-css@1.3.2 # CSS minifier run for production mode +standard-minifier-js@1.2.1 # JS minifier run for production mode +es5-shim@4.6.15 # ECMAScript 5 compatibility for older browsers. +ecmascript@0.6.1 # Enable ECMAScript2015+ syntax in app code +shell-server@0.2.1 # Server-side component of the `meteor shell` command -# Atmosphere +accounts-base@1.2.14 +check@1.2.4 +logging@1.1.16 +mdg:validated-method kadira:flow-router kadira:blaze-layout arillo:flow-router-helpers @@ -31,5 +31,6 @@ aldeed:autoform aldeed:collection2 aldeed:simple-schema alanning:roles -twbs:bootstrap -momentjs:moment \ No newline at end of file +themeteorchef:bert +fourseven:scss +fortawesome:fontawesome diff --git a/.meteor/release b/.meteor/release index 3a05e0a..61f6c67 100644 --- a/.meteor/release +++ b/.meteor/release @@ -1 +1 @@ -METEOR@1.2.1 +METEOR@1.4.2.3 diff --git a/.meteor/versions b/.meteor/versions index 2b05d37..8217c00 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -1,80 +1,96 @@ -accounts-base@1.2.2 -alanning:roles@1.2.14 -aldeed:autoform@5.7.1 -aldeed:collection2@2.5.0 -aldeed:simple-schema@1.3.3 -arillo:flow-router-helpers@0.4.5 -autoupdate@1.2.4 -babel-compiler@5.8.24_1 -babel-runtime@0.1.4 -base64@1.0.4 -binary-heap@1.0.4 -blaze@2.1.3 -blaze-html-templates@1.0.1 -blaze-tools@1.0.4 -boilerplate-generator@1.0.4 -caching-compiler@1.0.0 -caching-html-compiler@1.0.2 -callback-hook@1.0.4 -check@1.1.0 -coffeescript@1.0.11 -cosmos:browserify@0.5.1 -ddp@1.2.2 -ddp-client@1.2.1 -ddp-common@1.2.2 -ddp-rate-limiter@1.0.0 -ddp-server@1.2.2 -deps@1.0.9 -diff-sequence@1.0.1 -ecmascript@0.1.6 -ecmascript-runtime@0.2.6 -ejson@1.0.7 -fastclick@1.0.7 -geojson-utils@1.0.4 -hot-code-push@1.0.0 -html-tools@1.0.5 -htmljs@1.0.5 -http@1.1.1 -id-map@1.0.4 -jquery@1.11.4 -kadira:blaze-layout@2.2.0 -kadira:flow-router@2.7.0 -launch-screen@1.0.4 -livedata@1.0.15 -localstorage@1.0.5 -logging@1.0.8 -meteor@1.1.10 -meteor-base@1.0.1 -minifiers@1.1.7 -minimongo@1.0.10 -mobile-experience@1.0.1 -mobile-status-bar@1.0.6 +accounts-base@1.2.14 +alanning:roles@1.2.15 +aldeed:autoform@5.8.1 +aldeed:collection2@2.10.0 +aldeed:collection2-core@1.2.0 +aldeed:schema-deny@1.1.0 +aldeed:schema-index@1.1.1 +aldeed:simple-schema@1.5.3 +allow-deny@1.0.5 +arillo:flow-router-helpers@0.5.2 +autoupdate@1.3.12 +babel-compiler@6.13.0 +babel-runtime@1.0.1 +base64@1.0.10 +binary-heap@1.0.10 +blaze@2.1.9 +blaze-html-templates@1.0.5 +blaze-tools@1.0.10 +boilerplate-generator@1.0.11 +caching-compiler@1.1.9 +caching-html-compiler@1.0.7 +callback-hook@1.0.10 +check@1.2.4 +coffeescript@1.11.1_4 +ddp@1.2.5 +ddp-client@1.3.2 +ddp-common@1.2.8 +ddp-rate-limiter@1.0.6 +ddp-server@1.3.12 +deps@1.0.12 +diff-sequence@1.0.7 +ecmascript@0.6.1 +ecmascript-runtime@0.3.15 +ejson@1.0.13 +es5-shim@4.6.15 +fastclick@1.0.13 +fortawesome:fontawesome@4.6.3 +fourseven:scss@3.13.0 +geojson-utils@1.0.10 +hot-code-push@1.0.4 +html-tools@1.0.11 +htmljs@1.0.11 +http@1.2.10 +id-map@1.0.9 +jquery@1.11.10 +kadira:blaze-layout@2.3.0 +kadira:flow-router@2.12.1 +launch-screen@1.1.0 +livedata@1.0.18 +localstorage@1.0.12 +logging@1.1.16 +mdg:validated-method@1.1.0 +mdg:validation-error@0.5.1 +meteor@1.6.0 +meteor-base@1.0.4 +minifier-css@1.2.15 +minifier-js@1.2.15 +minimongo@1.0.19 +mobile-experience@1.0.4 +mobile-status-bar@1.0.13 +modules@0.7.7 +modules-runtime@0.7.7 momentjs:moment@2.10.6 -mongo@1.1.3 -mongo-id@1.0.1 -npm-mongo@1.4.39_1 -observe-sequence@1.0.7 -ordered-dict@1.0.4 -promise@0.5.1 -random@1.0.5 -rate-limit@1.0.0 -reactive-dict@1.1.3 -reactive-var@1.0.6 -reload@1.1.4 -retry@1.0.4 -routepolicy@1.0.6 -service-configuration@1.0.5 -session@1.1.1 -spacebars@1.0.7 -spacebars-compiler@1.0.7 -standard-minifiers@1.0.2 -templating@1.1.5 -templating-tools@1.0.0 -tracker@1.0.9 -twbs:bootstrap@3.3.5 -ui@1.0.8 -underscore@1.0.4 -url@1.0.5 -webapp@1.2.3 -webapp-hashing@1.0.5 +mongo@1.1.14 +mongo-id@1.0.6 +npm-mongo@2.2.11_2 +observe-sequence@1.0.14 +ordered-dict@1.0.9 +promise@0.8.8 +raix:eventemitter@0.1.3 +random@1.0.10 +rate-limit@1.0.6 +reactive-dict@1.1.8 +reactive-var@1.0.11 +reload@1.1.11 +retry@1.0.9 +routepolicy@1.0.12 +service-configuration@1.0.11 +session@1.1.7 +shell-server@0.2.1 +spacebars@1.0.13 +spacebars-compiler@1.0.13 +standard-minifier-css@1.3.2 +standard-minifier-js@1.2.1 +templating@1.2.15 +templating-compiler@1.2.15 +templating-runtime@1.2.15 +templating-tools@1.0.5 +themeteorchef:bert@2.1.1 +tracker@1.1.1 +ui@1.0.12 +underscore@1.0.10 +url@1.0.11 +webapp@1.3.12 +webapp-hashing@1.0.9 zimme:active-route@2.3.2 diff --git a/HISTORY.md b/HISTORY.md deleted file mode 100644 index c303743..0000000 --- a/HISTORY.md +++ /dev/null @@ -1,4 +0,0 @@ -# History / Changelog - -## vx.xx / xxxx-xx-xx - * Note \ No newline at end of file diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..108f3d3 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2016 Kjetil Haugland + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/NOTES.md b/NOTES.md deleted file mode 100755 index c69ed5e..0000000 --- a/NOTES.md +++ /dev/null @@ -1,12 +0,0 @@ -# Notes - -## Known bugs - * Note - - -## Todo - * Note - - -## Other - * Note \ No newline at end of file diff --git a/README.md b/README.md index 3eb1bf9..8eab3ce 100755 --- a/README.md +++ b/README.md @@ -3,12 +3,15 @@ A boilerplate for Meteor - giving you a simple and more organized way to create It comes with a complete collection sample including publications, subscriptions and CRUD functionality. Routes, views and some nice helpers are also included. -Take a look at [meteor-skeleton.meteor.com](http://meteor-skeleton.meteor.com) for a live sample. +Take a look at [meteorskeleton.herokuapp.com](https://meteorskeleton.herokuapp.com) for a demo. -![Meteor-skeleton](http://i.imgur.com/ETTVDTM.png) +![Meteor-skeleton](http://i.imgur.com/Soq1xnF.png) ## Packages used +### Atmosphere + +- blaze-html-templates - accounts-base - alanning:roles - kadira:flow-router @@ -18,51 +21,63 @@ Take a look at [meteor-skeleton.meteor.com](http://meteor-skeleton.meteor.com) f - aldeed:simple-schema - aldeed:collection2 - aldeed:autoform -- momentjs:moment -- twbs:bootstrap +- fourseven:scss +- themeteorchef:bert +- fortawesome:fontawesome + +### NPM + +- bootstrap-sass +- moment The Meteor packages 'autopublish' and 'insecure' are removed by default. +### NPM + ## Usage -1. Clone it: ```git clone https://github.com/kjetilhau/meteor-skeleton.git``` -2. ```cd meteor-skeleton``` +1. Clone it: `git clone https://github.com/kjetilhau/meteor-skeleton.git` +2. `cd meteor-skeleton` 3. Remove the .git folder -4. ```git init``` -6. ```meteor``` +4. `git init` +6. `meteor` ## Structure ``` -client/ # Client code - config/ # Configuration files - lib/ # Library files that get executed first - helpers/ # Helpers that helps you and yours - routes/ # Everything related to client-side routing - startup/ # Stuff that gets launched at client load - stylesheets/ # CSS/LESS/SCSS files - components/ # Styles for specific components - sites/ # Styles for sites and collections - subscriptions/ # Collection subscriptions that are not defined in routes - views/ # View templates - documents/ # Views related to the Documents collection - layouts/ # Layout files defined with Iron Router - pages/ # Views for static pages - shared/ # Usually templates that are shared between views -lib/ # Code shared with client and server files - collections/ # Collection files, separate files for each collection - helpers/ # Helpers that is accessible on both client and server -public/ # Public files - img/ # Static image folder - fonts/ # Static fonts folder -server/ # Server code - config/ # Server configuration files - fixtures/ # Fixtures for defining pre-loaded data - lib/ # Server-side library folder - publications/ # Collection publications, separate files for each collection - startup/ # Stuff that gets launched at server startup +client +import + api/ + documents/ + both/ + schemas/ + server/ + modules/ + startup/ + both/ + client/ + router/ + server/ + ui/ + components/ + documents/ + edit/ + index/ + documents-index-item/ + new/ + show/ + helpers/ + layouts/ + pages/ + shared/ + stylesheets/ + theme/ +public + img/ + fonts/ +server ``` ## Other great boilerplates +- [base](https://github.com/themeteorchef/base) by The Meteor Chef - [meteor-boilerplate](https://github.com/matteodem/meteor-boilerplate) by matteodem -- [Void](https://github.com/SachaG/Void) by Sacha Greif -- [meteor-boilerplate](https://github.com/BeDifferential/meteor-boilerplate) by BeDifferential +- [meteor-boilerplate](https://github.com/Differential/meteor-boilerplate) by Differential diff --git a/client/head.html b/client/head.html new file mode 100644 index 0000000..f59de57 --- /dev/null +++ b/client/head.html @@ -0,0 +1,12 @@ + + + Meteor-skeleton + + + + + + + + + diff --git a/client/lib/autoform_hooks.js b/client/lib/autoform_hooks.js deleted file mode 100755 index 55a78ff..0000000 --- a/client/lib/autoform_hooks.js +++ /dev/null @@ -1,25 +0,0 @@ -// *************************************************************** -// AUTOFORM HOOKS -// *************************************************************** - -// Logs a simple message to the console and re-routes if successful -AutoForm.addHooks(['documentForm'], { - after: { - insert: function(error, result) { - if (error) { - console.log("Insert Error:", error); - } else { - console.log("Document inserted:", result); - FlowRouter.go('documentsIndex'); - } - }, - update: function(error) { - if (error) { - console.log("Update Error:", error); - } else { - console.log("Document updated"); - FlowRouter.go('documentsIndex'); - } - } - } -}); diff --git a/client/main.js b/client/main.js new file mode 100644 index 0000000..f6c46a3 --- /dev/null +++ b/client/main.js @@ -0,0 +1,2 @@ +import '/imports/startup/client/_main.js'; +import '/imports/startup/both/_main.js'; diff --git a/client/main.scss b/client/main.scss new file mode 100644 index 0000000..9b643d2 --- /dev/null +++ b/client/main.scss @@ -0,0 +1,4 @@ +/* Load client styles +-------------------------------------------------- */ + +@import "{}/imports/ui/stylesheets/bundle.scss"; diff --git a/client/routes/documents.js b/client/routes/documents.js deleted file mode 100755 index 6cac798..0000000 --- a/client/routes/documents.js +++ /dev/null @@ -1,39 +0,0 @@ -// *************************************************************** -// ROUTES (Documents) -// *************************************************************** - -// DOCUMENTS INDEX -// ------------------------------------------------------- -FlowRouter.route('/documents', { - action: function() { - BlazeLayout.render("layout", {header: "header", main: "documentsIndex", footer: "footer"}); - }, - name: "documentsIndex" -}); - -// DOCUMENT NEW -// ------------------------------------------------------- -FlowRouter.route('/documents/new', { - action: function() { - BlazeLayout.render("layout", {header: "header", main: "documentNew", footer: "footer"}); - }, - name: "documentNew" -}); - -// DOCUMENT SHOW -// ------------------------------------------------------- -FlowRouter.route('/documents/:documentId', { - action: function() { - BlazeLayout.render("layout", {header: "header", main: "documentShow", footer: "footer"}); - }, - name: "documentShow" -}); - -// DOCUMENT EDIT -// ------------------------------------------------------- -FlowRouter.route('/documents/:documentId/edit', { - action: function() { - BlazeLayout.render("layout", {header: "header", main: "documentEdit", footer: "footer"}); - }, - name: "documentEdit" -}); \ No newline at end of file diff --git a/client/routes/filters.js b/client/routes/filters.js deleted file mode 100755 index 2ab552b..0000000 --- a/client/routes/filters.js +++ /dev/null @@ -1,14 +0,0 @@ -// *************************************************************** -// ROUTER FILTERS & TRIGGERS -// *************************************************************** - -function mustBeLoggedIn(context, redirect, stop) { - if (!Meteor.userId()) { - // if the user is not logged in, render the front page - redirect('frontpage'); - console.log("Must be logged in!"); - } -} - -// Uncomment to require the user to be logged in... -// FlowRouter.triggers.enter([mustBeLoggedIn], {except: ["frontpage", "about"]}); diff --git a/client/routes/pages.js b/client/routes/pages.js deleted file mode 100755 index 0ef8ec6..0000000 --- a/client/routes/pages.js +++ /dev/null @@ -1,21 +0,0 @@ -// *************************************************************** -// STATIC PAGES -// *************************************************************** - -// FRONTPAGE -// ------------------------------------------------------- -FlowRouter.route('/', { - action: function() { - BlazeLayout.render("layout", {header: "header", main: "frontpage", footer: "footer"}); - }, - name: "frontpage" -}); - -// ABOUT -// ------------------------------------------------------- -FlowRouter.route('/about', { - action: function() { - BlazeLayout.render("layout", {header: "header", main: "about", footer: "footer"}); - }, - name: "about" -}); \ No newline at end of file diff --git a/client/views/documents/document_edit.html b/client/views/documents/document_edit.html deleted file mode 100755 index 782332d..0000000 --- a/client/views/documents/document_edit.html +++ /dev/null @@ -1,20 +0,0 @@ - \ No newline at end of file diff --git a/client/views/documents/document_edit.js b/client/views/documents/document_edit.js deleted file mode 100755 index 01f2c2e..0000000 --- a/client/views/documents/document_edit.js +++ /dev/null @@ -1,26 +0,0 @@ -Template.documentEdit.onCreated(function() { - var self = this; - self.autorun(function () { - var documentId = FlowRouter.getParam('documentId'); - self.subscribe("document", documentId); - }); -}); - -Template.documentEdit.onRendered(function() { - // Reset form validations - AutoForm.resetForm('documentForm'); -}); - -Template.documentEdit.onDestroyed(function() { -}); - -Template.documentEdit.helpers({ - document: function () { - var documentId = FlowRouter.getParam('documentId'); - var document = Documents.findOne({_id: documentId}) || {}; - return document; - } -}); - -Template.documentEdit.events ({ -}); diff --git a/client/views/documents/document_new.html b/client/views/documents/document_new.html deleted file mode 100755 index 1dc49dc..0000000 --- a/client/views/documents/document_new.html +++ /dev/null @@ -1,13 +0,0 @@ - \ No newline at end of file diff --git a/client/views/documents/document_new.js b/client/views/documents/document_new.js deleted file mode 100755 index b386463..0000000 --- a/client/views/documents/document_new.js +++ /dev/null @@ -1,16 +0,0 @@ -Template.documentNew.onCreated(function() { -}); - -Template.documentNew.onRendered(function() { - // Reset form validations - AutoForm.resetForm('documentForm'); -}); - -Template.documentNew.onDestroyed(function() { -}); - -Template.documentNew.helpers({ -}); - -Template.documentNew.events ({ -}); diff --git a/client/views/documents/document_show.html b/client/views/documents/document_show.html deleted file mode 100755 index 171d7e6..0000000 --- a/client/views/documents/document_show.html +++ /dev/null @@ -1,13 +0,0 @@ - \ No newline at end of file diff --git a/client/views/documents/document_show.js b/client/views/documents/document_show.js deleted file mode 100755 index 4a41754..0000000 --- a/client/views/documents/document_show.js +++ /dev/null @@ -1,24 +0,0 @@ -Template.documentShow.onCreated(function() { - var self = this; - self.autorun(function () { - var documentId = FlowRouter.getParam('documentId'); - self.subscribe("document", documentId); - }); -}); - -Template.documentShow.onRendered(function() { -}); - -Template.documentShow.onDestroyed(function() { -}); - -Template.documentShow.helpers({ - document: function () { - var documentId = FlowRouter.getParam('documentId'); - var document = Documents.findOne({_id: documentId}) || {}; - return document; - } -}); - -Template.documentShow.events ({ -}); diff --git a/client/views/documents/documents_index.html b/client/views/documents/documents_index.html deleted file mode 100755 index 1ba88ab..0000000 --- a/client/views/documents/documents_index.html +++ /dev/null @@ -1,45 +0,0 @@ - diff --git a/client/views/documents/documents_index.js b/client/views/documents/documents_index.js deleted file mode 100755 index 7e98fc0..0000000 --- a/client/views/documents/documents_index.js +++ /dev/null @@ -1,27 +0,0 @@ -Template.documentsIndex.onCreated(function() { - this.subscribe('documents'); -}); - -Template.documentsIndex.onRendered(function() { -}); - -Template.documentsIndex.onDestroyed(function() { -}); - -Template.documentsIndex.helpers({ - documents: function () { - return Documents.find({}, {sort: {createdAt: -1}}); - } -}); - -Template.documentsIndex.events ({ - 'click .delete-document': function(e) { - e.preventDefault(); - var item = this; - - if (confirm("Are you sure?")) { - Documents.remove(item._id); - console.log("Document deleted") - } - } -}); diff --git a/client/views/layouts/layout.html b/client/views/layouts/layout.html deleted file mode 100755 index 8a9c8cf..0000000 --- a/client/views/layouts/layout.html +++ /dev/null @@ -1,13 +0,0 @@ - diff --git a/client/views/main.html b/client/views/main.html deleted file mode 100755 index 4a2270b..0000000 --- a/client/views/main.html +++ /dev/null @@ -1,7 +0,0 @@ - - Meteor-skeleton - - - - - \ No newline at end of file diff --git a/client/views/pages/about.html b/client/views/pages/about.html deleted file mode 100755 index dc8b7cb..0000000 --- a/client/views/pages/about.html +++ /dev/null @@ -1,99 +0,0 @@ - diff --git a/client/views/pages/frontpage.html b/client/views/pages/frontpage.html deleted file mode 100755 index 3b53f4a..0000000 --- a/client/views/pages/frontpage.html +++ /dev/null @@ -1,12 +0,0 @@ - diff --git a/client/views/shared/401.html b/client/views/shared/401.html deleted file mode 100755 index b020ed7..0000000 --- a/client/views/shared/401.html +++ /dev/null @@ -1,5 +0,0 @@ - \ No newline at end of file diff --git a/client/views/shared/404.html b/client/views/shared/404.html deleted file mode 100755 index 1c7771a..0000000 --- a/client/views/shared/404.html +++ /dev/null @@ -1,5 +0,0 @@ - \ No newline at end of file diff --git a/client/views/shared/footer.html b/client/views/shared/footer.html deleted file mode 100755 index fc4f965..0000000 --- a/client/views/shared/footer.html +++ /dev/null @@ -1,9 +0,0 @@ - diff --git a/client/views/shared/loading.html b/client/views/shared/loading.html deleted file mode 100644 index 88e2da3..0000000 --- a/client/views/shared/loading.html +++ /dev/null @@ -1,3 +0,0 @@ - diff --git a/imports/api/documents/both/document-collection.js b/imports/api/documents/both/document-collection.js new file mode 100644 index 0000000..f31c00e --- /dev/null +++ b/imports/api/documents/both/document-collection.js @@ -0,0 +1,26 @@ +import { Mongo } from 'meteor/mongo'; +import { SimpleSchema } from 'meteor/aldeed:simple-schema'; + +import DocumentSchema from './schemas/document-schema'; + +// *************************************************************** +// DOCUMENTS Collection +// *************************************************************** + +export const Documents = new Mongo.Collection('documents'); + +// We use explicit methods, so deny everything +Documents.allow({ + insert() { return false; }, + update() { return false; }, + remove() { return false; }, +}); + +Documents.deny({ + insert() { return true; }, + update() { return true; }, + remove() { return true; }, +}); + +// Must remember to attach the schema to the collection +Documents.attachSchema(DocumentSchema); diff --git a/imports/api/documents/both/document-methods.js b/imports/api/documents/both/document-methods.js new file mode 100644 index 0000000..4383c3e --- /dev/null +++ b/imports/api/documents/both/document-methods.js @@ -0,0 +1,64 @@ +import { Meteor } from 'meteor/meteor'; +import { SimpleSchema } from 'meteor/aldeed:simple-schema'; +import { ValidatedMethod } from 'meteor/mdg:validated-method'; + +import { Documents } from './document-collection.js'; +import CreateDocumentSchema from './schemas/create-document-schema.js'; +import UpdateDocumentSchema from './schemas/update-document-schema.js'; + +// *************************************************************** +// METHODS (related to the documents collection) +// *************************************************************** + +export const createDocument = new ValidatedMethod({ + name: 'documents.create', + validate: CreateDocumentSchema.validator(), + run(document) { + // Additional data verification + + return Documents.insert({ + title: document.title, + content: document.content + }, function (error, result) { + if (error) { + throw new Meteor.Error(500, "Server error"); + } + }); + } +}); + +export const updateDocument = new ValidatedMethod({ + name: 'documents.update', + validate: UpdateDocumentSchema.validator(), + run(document) { + // Additional data verification + + return Documents.update(document._id, { + $set: { + title: document.title, + content: document.content + } + }, function (error, result) { + if (error) { + throw new Meteor.Error(500, "Server error"); + } + } + ); + } +}); + +export const deleteDocument = new ValidatedMethod({ + name: 'documents.delete', + validate: new SimpleSchema({ + documentId: { type: String } + }).validator(), + run({documentId}) { + // Additional data verification + + return Documents.remove(documentId, function (error, result) { + if (error) { + throw new Meteor.Error(500, "Server error"); + } + }); + } +}); diff --git a/imports/api/documents/both/schemas/create-document-schema.js b/imports/api/documents/both/schemas/create-document-schema.js new file mode 100644 index 0000000..2f26f55 --- /dev/null +++ b/imports/api/documents/both/schemas/create-document-schema.js @@ -0,0 +1,22 @@ +import { SimpleSchema } from 'meteor/aldeed:simple-schema'; + +// *************************************************************** +// Create document schema +// *************************************************************** + +const CreateDocumentSchema = new SimpleSchema({ + title: { + type: String, + label: "Title", + max: 120, + optional: false + }, + content: { + type: String, + label: "Content", + max: 1000, + optional: true + }, +}); + +export default CreateDocumentSchema; diff --git a/imports/api/documents/both/schemas/document-schema.js b/imports/api/documents/both/schemas/document-schema.js new file mode 100644 index 0000000..c69530b --- /dev/null +++ b/imports/api/documents/both/schemas/document-schema.js @@ -0,0 +1,77 @@ +import { SimpleSchema } from 'meteor/aldeed:simple-schema'; + +// *************************************************************** +// Document schema +// *************************************************************** + +const DocumentSchema = new SimpleSchema({ + title: { + type: String, + label: "Title", + max: 120, + optional: false + }, + content: { + type: String, + label: "Content", + max: 1000, + optional: true + }, + createdAt: { + type: Date, + optional: true, + denyUpdate: true, + autoValue: function () { + if (this.isInsert) { + return new Date(); + } + } + }, + updatedAt: { + type: Date, + optional: true, + denyInsert: true, + autoValue: function () { + if (this.isUpdate) { + return new Date(); + } + } + } +}); + +// Custom validation messages with SimpleSchema. Remove if not needed +DocumentSchema.messages({ + required: "[label] is required", + minString: "[label] must be at least [min] characters", + maxString: "[label] cannot exceed [max] characters", + minNumber: "[label] must be at least [min]", + maxNumber: "[label] cannot exceed [max]", + minDate: "[label] must be on or after [min]", + maxDate: "[label] cannot be after [max]", + badDate: "[label] is not a valid date", + minCount: "You must specify at least [minCount] values", + maxCount: "You cannot specify more than [maxCount] values", + noDecimal: "[label] must be an integer", + notAllowed: "[value] is not an allowed value", + expectedString: "[label] must be a string", + expectedNumber: "[label] must be a number", + expectedBoolean: "[label] must be a boolean", + expectedArray: "[label] must be an array", + expectedObject: "[label] must be an object", + expectedConstructor: "[label] must be a [type]", + regEx: [ + { msg: "[label] failed regular expression validation" }, + { exp: SimpleSchema.RegEx.Email, msg: "[label] must be a valid e-mail address" }, + { exp: SimpleSchema.RegEx.WeakEmail, msg: "[label] must be a valid e-mail address" }, + { exp: SimpleSchema.RegEx.Domain, msg: "[label] must be a valid domain" }, + { exp: SimpleSchema.RegEx.WeakDomain, msg: "[label] must be a valid domain" }, + { exp: SimpleSchema.RegEx.IP, msg: "[label] must be a valid IPv4 or IPv6 address" }, + { exp: SimpleSchema.RegEx.IPv4, msg: "[label] must be a valid IPv4 address" }, + { exp: SimpleSchema.RegEx.IPv6, msg: "[label] must be a valid IPv6 address" }, + { exp: SimpleSchema.RegEx.Url, msg: "[label] must be a valid URL" }, + { exp: SimpleSchema.RegEx.Id, msg: "[label] must be a valid alphanumeric ID" } + ], + keyNotInSchema: "[key] is not allowed by the schema" +}); + +export default DocumentSchema; diff --git a/imports/api/documents/both/schemas/update-document-schema.js b/imports/api/documents/both/schemas/update-document-schema.js new file mode 100644 index 0000000..bfa7df2 --- /dev/null +++ b/imports/api/documents/both/schemas/update-document-schema.js @@ -0,0 +1,26 @@ +import { SimpleSchema } from 'meteor/aldeed:simple-schema'; + +// *************************************************************** +// Update document schema +// *************************************************************** + +const UpdateDocumentSchema = new SimpleSchema({ + _id: { + type: String, + optional: false + }, + title: { + type: String, + label: "Title", + max: 120, + optional: false + }, + content: { + type: String, + label: "Content", + max: 1000, + optional: true + }, +}); + +export default UpdateDocumentSchema; diff --git a/imports/api/documents/server/document-publications.js b/imports/api/documents/server/document-publications.js new file mode 100644 index 0000000..d2fd928 --- /dev/null +++ b/imports/api/documents/server/document-publications.js @@ -0,0 +1,24 @@ +import { Meteor } from 'meteor/meteor'; +import { SimpleSchema } from 'meteor/aldeed:simple-schema'; + +import { Documents } from '../both/document-collection.js' + +// *************************************************************** +// PUBLICATIONS (For the documents collection) +// *************************************************************** + +// DOCUMENTS INDEX +// ------------------------------------------------------- +Meteor.publish('documents.all', function documentsAll() { + return Documents.find(); +}); + +// DOCUMENT SHOW +// ------------------------------------------------------- +Meteor.publish('documents.single', function documentsSingle(id) { + new SimpleSchema({ + id: { type: String } + }).validate({ id }); + + return Documents.find(id); +}); diff --git a/client/lib/helpers/common.js b/imports/modules/helpers.js old mode 100755 new mode 100644 similarity index 51% rename from client/lib/helpers/common.js rename to imports/modules/helpers.js index a362ef5..28084b6 --- a/client/lib/helpers/common.js +++ b/imports/modules/helpers.js @@ -1,52 +1,54 @@ // *************************************************************** -// COMMON HELPERS (client-side only) +// Helpers // *************************************************************** +import moment from "moment"; + // Cheap pluralization -Template.registerHelper('pluralize', function(count, word) { +export const pluralize = (count, word) => { return count === 1 ? '1 ' + word : count + ' ' + word + 's'; -}); +}; // Outputs e.g. 12 days ago or 2 hours ago -Template.registerHelper('showTimeAgo', function(date) { +export const showTimeAgo = (date) => { return !date ? "" : moment(date).fromNow(); -}); +}; // Outputs e.g. Jan, 2013 -Template.registerHelper('showMonthYear', function(date) { +export const showMonthYear = (date) => { return !date ? "" : moment(date).format("MMM, YYYY"); -}); +}; // Outputs e.g. 12th Jan, 2013 -Template.registerHelper('showDayMonthYear', function(date) { - return !date ? "" : moment(date).format("Do MMM, YYYY") -}); +export const showDayMonthYear = (date) => { + return !date ? "" : moment(date).format("Do MMM, YYYY"); +}; // Outputs August 30th 2014, 5:33:46 pm -Template.registerHelper('showPrettyTimestamp', function(date) { - return !date ? "" : moment(date).format("MMMM Do YYYY, h:mm:ss a") -}); +export const showPrettyTimestamp = (date) => { + return !date ? "" : moment(date).format("MMMM Do YYYY, h:mm a"); +}; // Get profile image or placeholder image -Template.registerHelper('getProfileImage', function(image) { - var imagePlaceholder = "/img/profile_placeholder.png"; +export const getProfileImage = (image) => { + let imagePlaceholder = "/img/profile_placeholder.png"; if (!image || image === "") { return imagePlaceholder; } else { return image; } -}); +}; // Translates those bytes to something more readable (e.g. 1.2 MB) -Template.registerHelper('bytesToSize', function(bytes) { +export const bytesToSize = (bytes) => { if (!bytes) { return (""); } else { - var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']; + let sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']; if (bytes == 0) return 'n/a'; - var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024))); + let i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024))); return Math.round(bytes / Math.pow(1024, i), 2) + ' ' + sizes[i]; } -}); +}; diff --git a/imports/modules/permissions.js b/imports/modules/permissions.js new file mode 100644 index 0000000..2e7c619 --- /dev/null +++ b/imports/modules/permissions.js @@ -0,0 +1,19 @@ +// *************************************************************** +// Permissions +// *************************************************************** + +// If the user owns the item, give permission. Might want to edit this as needed. +export const canEditItem = (userId, item) => { + return userId === item.userId; +}; + +// If the user owns the item, give permission. Might want to edit this as needed. +export const canRemoveItem = (userId, item) => { + return userId === item.userId; +}; + +// Checks whether selected user or current user is admin (with the Roles package) +export const isAdmin = (user) => { + user = (typeof user === 'undefined') ? Meteor.user() : user; + return !!user && !!Roles.userIsInRole(user, ['admin']); +}; diff --git a/client/startup/startup.js b/imports/startup/both/_main.js old mode 100755 new mode 100644 similarity index 55% rename from client/startup/startup.js rename to imports/startup/both/_main.js index 49df221..974598a --- a/client/startup/startup.js +++ b/imports/startup/both/_main.js @@ -1,7 +1,6 @@ // *************************************************************** -// ON CLIENT STARTUP +// Bundle for client AND server modules // *************************************************************** -Meteor.startup(function () { - // Do something -}); +// Debug options. Turn off in production! +SimpleSchema.debug = true; diff --git a/imports/startup/client/_main.js b/imports/startup/client/_main.js new file mode 100644 index 0000000..e80814b --- /dev/null +++ b/imports/startup/client/_main.js @@ -0,0 +1,23 @@ +// *************************************************************** +// Bundle for client modules +// *************************************************************** + +// Main modules +import './router/index.js'; +import './accounts.js'; +import './subscriptions.js'; + +// Main templates +import '/imports/ui/layouts/layout.js'; +import '/imports/ui/shared/error-404/error-404.js'; +import '/imports/ui/shared/footer/footer.js'; +import '/imports/ui/shared/header/header.js'; +import '/imports/ui/shared/empty-result/empty-result.js'; +import '/imports/ui/shared/loader/loader.js'; + +// Blaze helpers +import '/imports/ui/helpers/handlebars-helpers.js'; +import '/imports/ui/helpers/handlebars-lists.js'; + +// Notifications +import './bert.js'; diff --git a/client/config/accounts.js b/imports/startup/client/accounts.js old mode 100755 new mode 100644 similarity index 81% rename from client/config/accounts.js rename to imports/startup/client/accounts.js index 5af9484..06d6a16 --- a/client/config/accounts.js +++ b/imports/startup/client/accounts.js @@ -1,5 +1,5 @@ // *************************************************************** -// ACCOUNTS CONFIGURATION (client-side) +// Meteor accounts configuration (client-side) // *************************************************************** //Accounts.ui.config({ diff --git a/imports/startup/client/bert.js b/imports/startup/client/bert.js new file mode 100644 index 0000000..e3be561 --- /dev/null +++ b/imports/startup/client/bert.js @@ -0,0 +1,16 @@ +// *************************************************************** +// Bert notification configuration +// *************************************************************** + +// Set notification defaults +Meteor.startup( () => { + Bert.defaults = { + hideDelay: 3500, + // Accepts: a number in milliseconds. + style: 'growl-bottom-right', + // Accepts: fixed-top, fixed-bottom, growl-top-left, growl-top-right, + // growl-bottom-left, growl-bottom-right. + type: 'info' + // Accepts: default, success, info, warning, danger. + }; +}); diff --git a/client/routes/config.js b/imports/startup/client/router/config.js old mode 100755 new mode 100644 similarity index 56% rename from client/routes/config.js rename to imports/startup/client/router/config.js index 5491280..d56509d --- a/client/routes/config.js +++ b/imports/startup/client/router/config.js @@ -1,5 +1,8 @@ +import { FlowRouter } from 'meteor/kadira:flow-router'; +import { BlazeLayout } from 'meteor/kadira:blaze-layout'; + // *************************************************************** -// FLOW ROUTER CONFIG +// Flow Router configuration // *************************************************************** // Not found route @@ -7,6 +10,6 @@ FlowRouter.notFound = { // Subscriptions registered here don't have Fast Render support. subscriptions: function() {}, action: function() { - BlazeLayout.render("layout", {header: "header", main: "404", footer: "footer"}); + BlazeLayout.render("layout", {header: "header", main: "error404", footer: "footer"}); } -}; \ No newline at end of file +}; diff --git a/imports/startup/client/router/documents.js b/imports/startup/client/router/documents.js new file mode 100644 index 0000000..4435fd6 --- /dev/null +++ b/imports/startup/client/router/documents.js @@ -0,0 +1,47 @@ +import { FlowRouter } from 'meteor/kadira:flow-router'; +import { BlazeLayout } from 'meteor/kadira:blaze-layout'; + +import '/imports/ui/components/documents/index/documents-index.js'; +import '/imports/ui/components/documents/new/document-new.js'; +import '/imports/ui/components/documents/show/document-show.js'; +import '/imports/ui/components/documents/edit/document-edit.js'; + +// *************************************************************** +// Document routes +// *************************************************************** + +// DOCUMENTS INDEX +// ------------------------------------------------------- +FlowRouter.route('/documents', { + action: function () { + BlazeLayout.render("layout", { header: "header", main: "documentsIndex", footer: "footer" }); + }, + name: "documentsIndex" +}); + +// DOCUMENT NEW +// ------------------------------------------------------- +FlowRouter.route('/documents/new', { + action: function () { + BlazeLayout.render("layout", { header: "header", main: "documentNew", footer: "footer" }); + }, + name: "documentNew" +}); + +// DOCUMENT SHOW +// ------------------------------------------------------- +FlowRouter.route('/documents/:documentId', { + action: function () { + BlazeLayout.render("layout", { header: "header", main: "documentShow", footer: "footer" }); + }, + name: "documentShow" +}); + +// DOCUMENT EDIT +// ------------------------------------------------------- +FlowRouter.route('/documents/:documentId/edit', { + action: function () { + BlazeLayout.render("layout", { header: "header", main: "documentEdit", footer: "footer" }); + }, + name: "documentEdit" +}); diff --git a/imports/startup/client/router/filters.js b/imports/startup/client/router/filters.js new file mode 100644 index 0000000..becbd59 --- /dev/null +++ b/imports/startup/client/router/filters.js @@ -0,0 +1,21 @@ +import { FlowRouter } from 'meteor/kadira:flow-router'; +import { BlazeLayout } from 'meteor/kadira:blaze-layout'; + +// *************************************************************** +// Route filters & triggers +// *************************************************************** + +// Simple redirect unless user is logged in +const mustBeLoggedIn = (context, redirect, stop) => { + if (!Meteor.userId()) { + redirect('frontpage'); + Bert.alert('Must be logged in!', 'danger'); + } +} + +/* +Uncomment to require the user to be logged in to view og modify documents +Note: This is only handled client-side. Remember to do verification on the server as well +*/ + +// FlowRouter.triggers.enter([mustBeLoggedIn], {except: ["frontpage", "about"]}); diff --git a/server/startup/startup.js b/imports/startup/client/router/index.js old mode 100755 new mode 100644 similarity index 53% rename from server/startup/startup.js rename to imports/startup/client/router/index.js index 376cf5a..7a722a5 --- a/server/startup/startup.js +++ b/imports/startup/client/router/index.js @@ -1,7 +1,9 @@ // *************************************************************** -// ON SERVER STARTUP +// Router bundle // *************************************************************** -Meteor.startup(function () { - Fixtures.Documents.Create(); -}); +// Routing +import './config.js'; +import './filters.js'; +import './pages.js'; +import './documents.js'; diff --git a/imports/startup/client/router/pages.js b/imports/startup/client/router/pages.js new file mode 100644 index 0000000..5925369 --- /dev/null +++ b/imports/startup/client/router/pages.js @@ -0,0 +1,27 @@ +import { FlowRouter } from 'meteor/kadira:flow-router'; +import { BlazeLayout } from 'meteor/kadira:blaze-layout'; + +import '/imports/ui/pages/frontpage/frontpage.js'; +import '/imports/ui/pages/about/about.js'; + +// *************************************************************** +// Static pages +// *************************************************************** + +// FRONTPAGE +// ------------------------------------------------------- +FlowRouter.route('/', { + action: function () { + BlazeLayout.render("layout", { header: "header", main: "frontpage", footer: "footer" }); + }, + name: "frontpage" +}); + +// ABOUT +// ------------------------------------------------------- +FlowRouter.route('/about', { + action: function () { + BlazeLayout.render("layout", { header: "header", main: "about", footer: "footer" }); + }, + name: "about" +}); diff --git a/client/subscriptions/subscriptions.js b/imports/startup/client/subscriptions.js old mode 100755 new mode 100644 similarity index 59% rename from client/subscriptions/subscriptions.js rename to imports/startup/client/subscriptions.js index dac6911..3b30604 --- a/client/subscriptions/subscriptions.js +++ b/imports/startup/client/subscriptions.js @@ -1,3 +1,4 @@ // *************************************************************** -// SUBSCRIPTIONS (global subscriptions) +// Global subscriptions +// Note: Template subscriptions are recommended for most use cases // *************************************************************** diff --git a/server/lib/namespaces.js b/imports/startup/server/_main.js old mode 100755 new mode 100644 similarity index 62% rename from server/lib/namespaces.js rename to imports/startup/server/_main.js index 3e31232..6586c2a --- a/server/lib/namespaces.js +++ b/imports/startup/server/_main.js @@ -1,6 +1,6 @@ // *************************************************************** -// Namespaces (only shared with server) +// Bundle for server modules // *************************************************************** -// Namespaces -Fixtures = {}; +import './fixtures.js'; +import './register-api.js'; diff --git a/server/fixtures/documents.js b/imports/startup/server/fixtures.js old mode 100755 new mode 100644 similarity index 69% rename from server/fixtures/documents.js rename to imports/startup/server/fixtures.js index ddc4e4b..6b02bc5 --- a/server/fixtures/documents.js +++ b/imports/startup/server/fixtures.js @@ -1,10 +1,11 @@ +import { Meteor } from 'meteor/meteor'; +import { Documents } from '/imports/api/documents/both/document-collection.js'; + // *************************************************************** -// FIXTURES (generate dummy data for the Documents collection) +// Fixtures (generate dummy data for the Documents collection) // *************************************************************** -Fixtures.Documents = {}; - -Fixtures.Documents.Create = function () { +Meteor.startup(() => { if (Documents.find().count() === 0) { Documents.insert({ title: "Derp", @@ -21,4 +22,4 @@ Fixtures.Documents.Create = function () { content: "Lorem ipsum, herp derp durr." }); } -} \ No newline at end of file +}); diff --git a/imports/startup/server/register-api.js b/imports/startup/server/register-api.js new file mode 100644 index 0000000..cdb16d7 --- /dev/null +++ b/imports/startup/server/register-api.js @@ -0,0 +1,8 @@ +// *************************************************************** +// API modules +// This defines all the collections, publications and methods that the application provides +// as an API to the client. +// *************************************************************** + +import '/imports/api/documents/both/document-methods.js'; +import '/imports/api/documents/server/document-publications.js'; diff --git a/imports/ui/components/documents/edit/document-edit-hooks.js b/imports/ui/components/documents/edit/document-edit-hooks.js new file mode 100644 index 0000000..1248ee4 --- /dev/null +++ b/imports/ui/components/documents/edit/document-edit-hooks.js @@ -0,0 +1,17 @@ +// *************************************************************** +// AUTOFORM HOOKS +// *************************************************************** + +// Shows a simple message and re-routes if successful +AutoForm.addHooks(['documentEditForm'], { + after: { + "method": (error, result) => { + if (error) { + console.log("Update Error:", error.reason); + } else { + FlowRouter.go('documentsIndex'); + Bert.alert('Document updated!'); + } + } + } +}); diff --git a/imports/ui/components/documents/edit/document-edit.html b/imports/ui/components/documents/edit/document-edit.html new file mode 100644 index 0000000..68a8d2c --- /dev/null +++ b/imports/ui/components/documents/edit/document-edit.html @@ -0,0 +1,21 @@ + diff --git a/imports/ui/components/documents/edit/document-edit.js b/imports/ui/components/documents/edit/document-edit.js new file mode 100644 index 0000000..c6dc29c --- /dev/null +++ b/imports/ui/components/documents/edit/document-edit.js @@ -0,0 +1,39 @@ +import { Meteor } from 'meteor/meteor'; +import { Template } from 'meteor/templating'; +import { Mongo } from 'meteor/mongo'; +import { Tracker } from 'meteor/tracker'; +import { $ } from 'meteor/jquery'; +import { SimpleSchema } from 'meteor/aldeed:simple-schema'; + +import { Documents } from '/imports/api/documents/both/document-collection.js'; +import UpdateDocumentSchema from '/imports/api/documents/both/schemas/update-document-schema.js'; + +import './document-edit.html'; +import './document-edit-hooks.js'; + +Template.documentEdit.onCreated(function () { + this.getDocumentId = () => FlowRouter.getParam('documentId'); + + this.autorun(() => { + this.subscribe('documents.single', this.getDocumentId()); + }); +}); + +Template.documentEdit.onRendered(function () { +}); + +Template.documentEdit.onDestroyed(function () { +}); + +Template.documentEdit.helpers({ + updateDocumentSchema: function () { + return UpdateDocumentSchema; + }, + document() { + let document = Documents.findOne({ _id: Template.instance().getDocumentId() }) || {}; + return document; + } +}); + +Template.documentEdit.events({ +}); diff --git a/client/stylesheets/components/footer.css b/imports/ui/components/documents/edit/document-edit.scss similarity index 56% rename from client/stylesheets/components/footer.css rename to imports/ui/components/documents/edit/document-edit.scss index 934a174..f9355d8 100644 --- a/client/stylesheets/components/footer.css +++ b/imports/ui/components/documents/edit/document-edit.scss @@ -1,6 +1,4 @@ -/* Footer +/* Document - Edit -------------------------------------------------- */ -.footer { - margin-top: 20px; -} \ No newline at end of file +.document-edit {} diff --git a/imports/ui/components/documents/index/documents-index-item/documents-index-item.html b/imports/ui/components/documents/index/documents-index-item/documents-index-item.html new file mode 100644 index 0000000..3e0f600 --- /dev/null +++ b/imports/ui/components/documents/index/documents-index-item/documents-index-item.html @@ -0,0 +1,14 @@ + diff --git a/imports/ui/components/documents/index/documents-index-item/documents-index-item.js b/imports/ui/components/documents/index/documents-index-item/documents-index-item.js new file mode 100644 index 0000000..1aa1a65 --- /dev/null +++ b/imports/ui/components/documents/index/documents-index-item/documents-index-item.js @@ -0,0 +1,51 @@ +import { Meteor } from 'meteor/meteor'; +import { Template } from 'meteor/templating'; +import { $ } from 'meteor/jquery'; + +import { deleteDocument } from '/imports/api/documents/both/document-methods.js'; + +import './documents-index-item.html'; + +Template.documentsIndexItem.onCreated(function () { + // Example for validating the data context (if needed) + this.autorun(() => { + new SimpleSchema({ + _id: { type: String }, + title: { type: String }, + content: { type: String, optional: true }, + createdAt: { type: Date }, + updatedAt: { type: Date, optional: true }, + }).validate(Template.currentData().document); + }); + + this.getDocumentId = () => Template.instance().data.document._id; +}); + +Template.documentsIndexItem.onRendered(function () { +}); + +Template.documentsIndexItem.onDestroyed(function () { +}); + +Template.documentsIndexItem.helpers({ +}); + +Template.documentsIndexItem.events({ + 'click .js-delete-document'(event, instance) { + event.preventDefault(); + + if (confirm("Are you sure?")) { + let documentId = Template.instance().getDocumentId(); + + deleteDocument.call({ + documentId: documentId + }, (error, result) => { + if (error) { + console.log(error.error) + } else { + Bert.alert('Document deleted!', 'danger'); + } + }); + } + } +}); diff --git a/imports/ui/components/documents/index/documents-index-item/documents-index-item.scss b/imports/ui/components/documents/index/documents-index-item/documents-index-item.scss new file mode 100644 index 0000000..5034a72 --- /dev/null +++ b/imports/ui/components/documents/index/documents-index-item/documents-index-item.scss @@ -0,0 +1,4 @@ +/* Documents - Index item +-------------------------------------------------- */ + +.documents-index-item {} diff --git a/imports/ui/components/documents/index/documents-index.html b/imports/ui/components/documents/index/documents-index.html new file mode 100644 index 0000000..3e4a1cc --- /dev/null +++ b/imports/ui/components/documents/index/documents-index.html @@ -0,0 +1,33 @@ + diff --git a/imports/ui/components/documents/index/documents-index.js b/imports/ui/components/documents/index/documents-index.js new file mode 100644 index 0000000..a2e357f --- /dev/null +++ b/imports/ui/components/documents/index/documents-index.js @@ -0,0 +1,29 @@ +import { Meteor } from 'meteor/meteor'; +import { Template } from 'meteor/templating'; +import { Mongo } from 'meteor/mongo'; +import { Tracker } from 'meteor/tracker'; +import { $ } from 'meteor/jquery'; + +import { Documents } from '/imports/api/documents/both/document-collection.js'; + +import './documents-index.html'; +import './documents-index-item/documents-index-item.js'; + +Template.documentsIndex.onCreated(function () { + this.subscribe('documents.all'); +}); + +Template.documentsIndex.onRendered(function () { +}); + +Template.documentsIndex.onDestroyed(function () { +}); + +Template.documentsIndex.helpers({ + documents() { + return Documents.find({}, { sort: { createdAt: -1 } }); + } +}); + +Template.documentsIndex.events({ +}); diff --git a/imports/ui/components/documents/index/documents-index.scss b/imports/ui/components/documents/index/documents-index.scss new file mode 100644 index 0000000..a378364 --- /dev/null +++ b/imports/ui/components/documents/index/documents-index.scss @@ -0,0 +1,6 @@ +/* Documents - Index +-------------------------------------------------- */ + +@import "{}/imports/ui/components/documents/index/documents-index-item/documents-index-item.scss"; + +.documents-index {} diff --git a/imports/ui/components/documents/new/document-new-hooks.js b/imports/ui/components/documents/new/document-new-hooks.js new file mode 100644 index 0000000..ed355d5 --- /dev/null +++ b/imports/ui/components/documents/new/document-new-hooks.js @@ -0,0 +1,17 @@ +// *************************************************************** +// AUTOFORM HOOKS +// *************************************************************** + +// Shows a simple message and re-routes if successful +AutoForm.addHooks(['documentNewForm'], { + after: { + "method": (error, result) => { + if (error) { + console.log("Insert Error:", error.reason); + } else { + FlowRouter.go('documentsIndex'); + Bert.alert('Document inserted!', 'success'); + } + } + } +}); diff --git a/imports/ui/components/documents/new/document-new.html b/imports/ui/components/documents/new/document-new.html new file mode 100644 index 0000000..329a230 --- /dev/null +++ b/imports/ui/components/documents/new/document-new.html @@ -0,0 +1,15 @@ + diff --git a/imports/ui/components/documents/new/document-new.js b/imports/ui/components/documents/new/document-new.js new file mode 100644 index 0000000..547756b --- /dev/null +++ b/imports/ui/components/documents/new/document-new.js @@ -0,0 +1,27 @@ +import { Meteor } from 'meteor/meteor'; +import { Template } from 'meteor/templating'; +import { $ } from 'meteor/jquery'; + +import { Documents } from '/imports/api/documents/both/document-collection.js'; +import CreateDocumentSchema from '/imports/api/documents/both/schemas/create-document-schema.js'; + +import './document-new.html'; +import './document-new-hooks.js'; + +Template.documentNew.onCreated(function () { +}); + +Template.documentNew.onRendered(function () { +}); + +Template.documentNew.onDestroyed(function () { +}); + +Template.documentNew.helpers({ + createDocumentSchema: function () { + return CreateDocumentSchema; + }, +}); + +Template.documentNew.events({ +}); diff --git a/imports/ui/components/documents/new/document-new.scss b/imports/ui/components/documents/new/document-new.scss new file mode 100644 index 0000000..e4cd16e --- /dev/null +++ b/imports/ui/components/documents/new/document-new.scss @@ -0,0 +1,4 @@ +/* Document - New +-------------------------------------------------- */ + +.document-new {} diff --git a/imports/ui/components/documents/show/document-show.html b/imports/ui/components/documents/show/document-show.html new file mode 100644 index 0000000..0a5b13a --- /dev/null +++ b/imports/ui/components/documents/show/document-show.html @@ -0,0 +1,20 @@ + diff --git a/imports/ui/components/documents/show/document-show.js b/imports/ui/components/documents/show/document-show.js new file mode 100644 index 0000000..f7da923 --- /dev/null +++ b/imports/ui/components/documents/show/document-show.js @@ -0,0 +1,33 @@ +import { Meteor } from 'meteor/meteor'; +import { Template } from 'meteor/templating'; +import { Mongo } from 'meteor/mongo'; +import { Tracker } from 'meteor/tracker'; +import { $ } from 'meteor/jquery'; + +import { Documents } from '/imports/api/documents/both/document-collection.js'; + +import './document-show.html'; + +Template.documentShow.onCreated(function () { + this.getDocumentId = () => FlowRouter.getParam('documentId'); + + this.autorun(() => { + this.subscribe('documents.single', this.getDocumentId()); + }); +}); + +Template.documentShow.onRendered(function () { +}); + +Template.documentShow.onDestroyed(function () { +}); + +Template.documentShow.helpers({ + document() { + let document = Documents.findOne({ _id: Template.instance().getDocumentId() }) || {}; + return document; + } +}); + +Template.documentShow.events({ +}); diff --git a/imports/ui/components/documents/show/document-show.scss b/imports/ui/components/documents/show/document-show.scss new file mode 100644 index 0000000..16f534f --- /dev/null +++ b/imports/ui/components/documents/show/document-show.scss @@ -0,0 +1,4 @@ +/* Document - Show +-------------------------------------------------- */ + +.document-show {} diff --git a/imports/ui/helpers/handlebars-helpers.js b/imports/ui/helpers/handlebars-helpers.js new file mode 100644 index 0000000..e882976 --- /dev/null +++ b/imports/ui/helpers/handlebars-helpers.js @@ -0,0 +1,40 @@ +// *************************************************************** +// COMMON HELPERS (client-side only) +// *************************************************************** + +import * as helpers from '/imports/modules/helpers.js'; + +// Cheap pluralization +Template.registerHelper('pluralize', (count, word) => { + return helpers.pluralize(count, word); +}); + +// Outputs e.g. 12 days ago or 2 hours ago +Template.registerHelper('showTimeAgo', (date) => { + return helpers.showTimeAgo(date); +}); + +// Outputs e.g. Jan, 2013 +Template.registerHelper('showMonthYear', (date) => { + return helpers.showMonthYear(date); +}); + +// Outputs e.g. 12th Jan, 2013 +Template.registerHelper('showDayMonthYear', (date) => { + return helpers.showDayMonthYear(date); +}); + +// Outputs August 30th 2014, 5:33:46 pm +Template.registerHelper('showPrettyTimestamp', (date) => { + return helpers.showPrettyTimestamp(date); +}); + +// Get profile image or placeholder image +Template.registerHelper('getProfileImage', (image) => { + return helpers.getProfileImage(image); +}); + +// Translates those bytes to something more readable (e.g. 1.2 MB) +Template.registerHelper('bytesToSize', (bytes) => { + return helpers.bytesToSize(bytes); +}); diff --git a/client/lib/helpers/lists.js b/imports/ui/helpers/handlebars-lists.js old mode 100755 new mode 100644 similarity index 93% rename from client/lib/helpers/lists.js rename to imports/ui/helpers/handlebars-lists.js index 19b3228..c639d5e --- a/client/lib/helpers/lists.js +++ b/imports/ui/helpers/handlebars-lists.js @@ -2,7 +2,7 @@ // LISTS (Example for use with Autoform) // *************************************************************** -Template.registerHelper("colors", function() { +Template.registerHelper("colors", () => { return [ {label: "#428bca", value: "#428bca"}, {label: "#a4bdfc", value: "#a4bdfc"}, diff --git a/imports/ui/layouts/layout.html b/imports/ui/layouts/layout.html new file mode 100644 index 0000000..55f41e9 --- /dev/null +++ b/imports/ui/layouts/layout.html @@ -0,0 +1,13 @@ + diff --git a/imports/ui/layouts/layout.js b/imports/ui/layouts/layout.js new file mode 100644 index 0000000..50ebb16 --- /dev/null +++ b/imports/ui/layouts/layout.js @@ -0,0 +1 @@ +import './layout.html'; diff --git a/client/stylesheets/common.css b/imports/ui/layouts/layout.scss old mode 100755 new mode 100644 similarity index 62% rename from client/stylesheets/common.css rename to imports/ui/layouts/layout.scss index 6cb8677..81488f0 --- a/client/stylesheets/common.css +++ b/imports/ui/layouts/layout.scss @@ -1,2 +1,4 @@ -/* Common +/* Layouts - Layout -------------------------------------------------- */ + +.layout {} diff --git a/imports/ui/pages/about/about.html b/imports/ui/pages/about/about.html new file mode 100644 index 0000000..80d40fd --- /dev/null +++ b/imports/ui/pages/about/about.html @@ -0,0 +1,132 @@ + diff --git a/imports/ui/pages/about/about.js b/imports/ui/pages/about/about.js new file mode 100644 index 0000000..07c9c36 --- /dev/null +++ b/imports/ui/pages/about/about.js @@ -0,0 +1 @@ +import './about.html'; diff --git a/client/stylesheets/sites/documents.css b/imports/ui/pages/about/about.scss old mode 100755 new mode 100644 similarity index 65% rename from client/stylesheets/sites/documents.css rename to imports/ui/pages/about/about.scss index e2d336c..d1039a0 --- a/client/stylesheets/sites/documents.css +++ b/imports/ui/pages/about/about.scss @@ -1,2 +1,4 @@ -/* Documents +/* Pages - About -------------------------------------------------- */ + +.about {} diff --git a/imports/ui/pages/frontpage/frontpage.html b/imports/ui/pages/frontpage/frontpage.html new file mode 100644 index 0000000..ff10c4b --- /dev/null +++ b/imports/ui/pages/frontpage/frontpage.html @@ -0,0 +1,14 @@ + diff --git a/imports/ui/pages/frontpage/frontpage.js b/imports/ui/pages/frontpage/frontpage.js new file mode 100644 index 0000000..e30f9ce --- /dev/null +++ b/imports/ui/pages/frontpage/frontpage.js @@ -0,0 +1 @@ +import './frontpage.html'; diff --git a/imports/ui/pages/frontpage/frontpage.scss b/imports/ui/pages/frontpage/frontpage.scss new file mode 100644 index 0000000..283c600 --- /dev/null +++ b/imports/ui/pages/frontpage/frontpage.scss @@ -0,0 +1,4 @@ +/* Pages - Frontpage +-------------------------------------------------- */ + +.frontpage {} diff --git a/imports/ui/shared/empty-result/empty-result.html b/imports/ui/shared/empty-result/empty-result.html new file mode 100644 index 0000000..78a62e4 --- /dev/null +++ b/imports/ui/shared/empty-result/empty-result.html @@ -0,0 +1,24 @@ + diff --git a/imports/ui/shared/empty-result/empty-result.js b/imports/ui/shared/empty-result/empty-result.js new file mode 100644 index 0000000..cfb7357 --- /dev/null +++ b/imports/ui/shared/empty-result/empty-result.js @@ -0,0 +1 @@ +import './empty-result.html'; diff --git a/imports/ui/shared/empty-result/empty-result.scss b/imports/ui/shared/empty-result/empty-result.scss new file mode 100644 index 0000000..ec5a849 --- /dev/null +++ b/imports/ui/shared/empty-result/empty-result.scss @@ -0,0 +1,29 @@ +/* Empty result +-------------------------------------------------- */ + +.empty-result { + text-align: center; + padding: 30px; + margin: 20px; + border: 3px dashed #e4e4e4; + border-radius: 5px; +} + +.empty-result__icon { + font-size: 9rem; + color: #D0D0D0; +} + +.empty-result__image { + margin-bottom: -5px; +} + +.empty-result__heading { + font-weight: 600; + letter-spacing: -1px; +} + +.empty-result__description { + font-size: 1.9rem; + color: #9f9f9f; +} diff --git a/imports/ui/shared/error-404/error-404.html b/imports/ui/shared/error-404/error-404.html new file mode 100644 index 0000000..9b60035 --- /dev/null +++ b/imports/ui/shared/error-404/error-404.html @@ -0,0 +1,7 @@ + diff --git a/imports/ui/shared/error-404/error-404.js b/imports/ui/shared/error-404/error-404.js new file mode 100644 index 0000000..d9e56d2 --- /dev/null +++ b/imports/ui/shared/error-404/error-404.js @@ -0,0 +1 @@ +import './error-404.html'; diff --git a/imports/ui/shared/error-404/error-404.scss b/imports/ui/shared/error-404/error-404.scss new file mode 100644 index 0000000..93e9f02 --- /dev/null +++ b/imports/ui/shared/error-404/error-404.scss @@ -0,0 +1,6 @@ +/* Shared - Error 404 +-------------------------------------------------- */ + +.error-404 { + margin-top: 20px; +} diff --git a/imports/ui/shared/footer/footer.html b/imports/ui/shared/footer/footer.html new file mode 100644 index 0000000..af48333 --- /dev/null +++ b/imports/ui/shared/footer/footer.html @@ -0,0 +1,9 @@ + diff --git a/imports/ui/shared/footer/footer.js b/imports/ui/shared/footer/footer.js new file mode 100644 index 0000000..a1d39a8 --- /dev/null +++ b/imports/ui/shared/footer/footer.js @@ -0,0 +1 @@ +import './footer.html'; diff --git a/imports/ui/shared/footer/footer.scss b/imports/ui/shared/footer/footer.scss new file mode 100644 index 0000000..536557b --- /dev/null +++ b/imports/ui/shared/footer/footer.scss @@ -0,0 +1,11 @@ +/* Shared - Footer +-------------------------------------------------- */ + +/* Simple sticky */ +.footer { + position: absolute; + bottom: 0; + width: 100%; + height: 60px; + background-color: #f5f5f5; +} diff --git a/client/views/shared/header.html b/imports/ui/shared/header/header.html old mode 100755 new mode 100644 similarity index 97% rename from client/views/shared/header.html rename to imports/ui/shared/header/header.html index e54b1f6..68b05ae --- a/client/views/shared/header.html +++ b/imports/ui/shared/header/header.html @@ -1,5 +1,6 @@ diff --git a/imports/ui/shared/header/header.js b/imports/ui/shared/header/header.js new file mode 100644 index 0000000..1319497 --- /dev/null +++ b/imports/ui/shared/header/header.js @@ -0,0 +1 @@ +import './header.html'; diff --git a/client/stylesheets/sites/frontpage.css b/imports/ui/shared/header/header.scss old mode 100755 new mode 100644 similarity index 63% rename from client/stylesheets/sites/frontpage.css rename to imports/ui/shared/header/header.scss index 50303e9..9718b33 --- a/client/stylesheets/sites/frontpage.css +++ b/imports/ui/shared/header/header.scss @@ -1,2 +1,4 @@ -/* Front page +/* Shared - Header -------------------------------------------------- */ + +.header {} diff --git a/imports/ui/shared/loader/loader.html b/imports/ui/shared/loader/loader.html new file mode 100644 index 0000000..436faf0 --- /dev/null +++ b/imports/ui/shared/loader/loader.html @@ -0,0 +1,8 @@ + diff --git a/imports/ui/shared/loader/loader.js b/imports/ui/shared/loader/loader.js new file mode 100644 index 0000000..81f5624 --- /dev/null +++ b/imports/ui/shared/loader/loader.js @@ -0,0 +1 @@ +import './loader.html'; diff --git a/imports/ui/shared/loader/loader.scss b/imports/ui/shared/loader/loader.scss new file mode 100644 index 0000000..15f7aad --- /dev/null +++ b/imports/ui/shared/loader/loader.scss @@ -0,0 +1,45 @@ +/* Shared - Loader +Credits: http://tobiasahlin.com/spinkit/ +-------------------------------------------------- */ + +.spinner { + width: 40px; + height: 40px; + + position: relative; + margin: 100px auto; +} + +.double-bounce1, .double-bounce2 { + width: 100%; + height: 100%; + border-radius: 50%; + background-color: #333; + opacity: 0.6; + position: absolute; + top: 0; + left: 0; + + -webkit-animation: sk-bounce 2.0s infinite ease-in-out; + animation: sk-bounce 2.0s infinite ease-in-out; +} + +.double-bounce2 { + -webkit-animation-delay: -1.0s; + animation-delay: -1.0s; +} + +@-webkit-keyframes sk-bounce { + 0%, 100% { -webkit-transform: scale(0.0) } + 50% { -webkit-transform: scale(1.0) } +} + +@keyframes sk-bounce { + 0%, 100% { + transform: scale(0.0); + -webkit-transform: scale(0.0); + } 50% { + transform: scale(1.0); + -webkit-transform: scale(1.0); + } +} diff --git a/imports/ui/stylesheets/bundle.scss b/imports/ui/stylesheets/bundle.scss new file mode 100644 index 0000000..3a363e0 --- /dev/null +++ b/imports/ui/stylesheets/bundle.scss @@ -0,0 +1,34 @@ +/* Style bundle +-------------------------------------------------- */ + +// Helpers +@import "{}/imports/ui/stylesheets/helpers.scss"; + +// Layouts +@import "{}/imports/ui/layouts/layout.scss"; + +// Shared +@import "{}/imports/ui/shared/header/header.scss"; +@import "{}/imports/ui/shared/footer/footer.scss"; +@import "{}/imports/ui/shared/error-404/error-404.scss"; +@import "{}/imports/ui/shared/empty-result/empty-result.scss"; +@import "{}/imports/ui/shared/loader/loader.scss"; + +// Pages +@import "{}/imports/ui/pages/frontpage/frontpage.scss"; +@import "{}/imports/ui/pages/about/about.scss"; + +// Components +@import "{}/imports/ui/components/documents/index/documents-index.scss"; +@import "{}/imports/ui/components/documents/show/document-show.scss"; +@import "{}/imports/ui/components/documents/edit/document-edit.scss"; +@import "{}/imports/ui/components/documents/new/document-new.scss"; + +// Bootstrap theme +@import "{}/imports/ui/stylesheets/theme/bootstrap_variables.scss"; + +// Bootstrap SASS library +@import '{}/node_modules/bootstrap-sass/assets/stylesheets/_bootstrap.scss'; + +// Base +@import "{}/imports/ui/stylesheets/common.scss"; diff --git a/imports/ui/stylesheets/common.scss b/imports/ui/stylesheets/common.scss new file mode 100644 index 0000000..e212c3d --- /dev/null +++ b/imports/ui/stylesheets/common.scss @@ -0,0 +1,14 @@ +/* Common +-------------------------------------------------- */ + +/* Sticky footer styles +-------------------------------------------------- */ +html { + position: relative; + min-height: 100%; +} + +body { + /* Margin bottom by footer height */ + margin-bottom: 60px; +} diff --git a/client/stylesheets/helpers.css b/imports/ui/stylesheets/helpers.scss similarity index 90% rename from client/stylesheets/helpers.css rename to imports/ui/stylesheets/helpers.scss index a82d3fd..9c18e16 100644 --- a/client/stylesheets/helpers.css +++ b/imports/ui/stylesheets/helpers.scss @@ -1,7 +1,17 @@ /* Helpers -------------------------------------------------- */ -/* Padding & margin */ +/* Margin & padding */ + +.m-0 { margin: 0px; } +.m-10 { margin: 10px; } +.m-20 { margin: 20px; } +.mt-0 { margin-top: 0px; } +.mt-10 { margin-top: 10px; } +.mt-20 { margin-top: 20px; } +.mb-0 { margin-bottom: 0px; } +.mb-10 { margin-bottom: 10px; } +.mb-20 { margin-bottom: 20px; } .p-0 { padding: 0px; } .p-10 { padding: 10px; } @@ -12,13 +22,3 @@ .pb-0 { padding-bottom: 0px; } .pb-10 { padding-bottom: 10px; } .pb-20 { padding-bottom: 20px; } - -.m-0 { margin: 0px; } -.m-10 { margin: 10px; } -.m-20 { margin: 20px; } -.mt-0 { margin-top: 0px; } -.mt-10 { margin-top: 10px; } -.mt-20 { margin-top: 20px; } -.mb-0 { margin-bottom: 0px; } -.mb-10 { margin-bottom: 10px; } -.mb-20 { margin-bottom: 20px; } \ No newline at end of file diff --git a/imports/ui/stylesheets/theme/bootstrap_variables.scss b/imports/ui/stylesheets/theme/bootstrap_variables.scss new file mode 100644 index 0000000..9e3ce7e --- /dev/null +++ b/imports/ui/stylesheets/theme/bootstrap_variables.scss @@ -0,0 +1,870 @@ +$bootstrap-sass-asset-helper: false !default; +// Cerulean 3.3.7 +// Variables +// -------------------------------------------------- + + +//== Colors +// +//## Gray and brand colors for use across Bootstrap. + +$gray-base: #000 !default; +$gray-darker: lighten($gray-base, 13.5%) !default; // #222 +$gray-dark: lighten($gray-base, 20%) !default; // #333 +$gray: lighten($gray-base, 33.5%) !default; // #555 +$gray-light: lighten($gray-base, 60%) !default; // #999 +$gray-lighter: lighten($gray-base, 93.5%) !default; // #eee + +$brand-primary: #2FA4E7 !default; +$brand-success: #73A839 !default; +$brand-info: #033C73 !default; +$brand-warning: #DD5600 !default; +$brand-danger: #C71C22 !default; + + +//== Scaffolding +// +//## Settings for some of the most global styles. + +//** Background color for ``. +$body-bg: #fff !default; +//** Global text color on ``. +$text-color: $gray !default; + +//** Global textual link color. +$link-color: $brand-primary !default; +//** Link hover color set via `darken()` function. +$link-hover-color: darken($link-color, 15%) !default; +//** Link hover decoration. +$link-hover-decoration: underline !default; + + +//== Typography +// +//## Font, line-height, and color for body text, headings, and more. + +$font-family-sans-serif: "Helvetica Neue", Helvetica, Arial, sans-serif !default; +$font-family-serif: Georgia, "Times New Roman", Times, serif !default; +//** Default monospace fonts for ``, ``, and `
`.
+$font-family-monospace:   Menlo, Monaco, Consolas, "Courier New", monospace !default;
+$font-family-base:        $font-family-sans-serif !default;
+
+$font-size-base:          14px !default;
+$font-size-large:         ceil(($font-size-base * 1.25)) !default; // ~18px
+$font-size-small:         ceil(($font-size-base * 0.85)) !default; // ~12px
+
+$font-size-h1:            floor(($font-size-base * 2.6)) !default; // ~36px
+$font-size-h2:            floor(($font-size-base * 2.15)) !default; // ~30px
+$font-size-h3:            ceil(($font-size-base * 1.7)) !default; // ~24px
+$font-size-h4:            ceil(($font-size-base * 1.25)) !default; // ~18px
+$font-size-h5:            $font-size-base !default;
+$font-size-h6:            ceil(($font-size-base * 0.85)) !default; // ~12px
+
+//** Unit-less `line-height` for use in components like buttons.
+$line-height-base:        1.428571429 !default; // 20/14
+//** Computed "line-height" (`font-size` * `line-height`) for use with `margin`, `padding`, etc.
+$line-height-computed:    floor(($font-size-base * $line-height-base)) !default; // ~20px
+
+//** By default, this inherits from the ``.
+$headings-font-family:    $font-family-base !default;
+$headings-font-weight:    500 !default;
+$headings-line-height:    1.2 !default;
+$headings-color:          inherit !default;
+
+
+//== Iconography
+//
+//## Specify custom location and filename of the included Glyphicons icon font. Useful for those including Bootstrap via Bower.
+
+//** Load fonts from this directory.
+$icon-font-path: if($bootstrap-sass-asset-helper, "bootstrap/", "../fonts/bootstrap/") !default;
+//** File name for all font files.
+$icon-font-name:          "glyphicons-halflings-regular" !default;
+//** Element ID within SVG icon file.
+$icon-font-svg-id:        "glyphicons_halflingsregular" !default;
+
+
+//== Components
+//
+//## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start).
+
+$padding-base-vertical:     8px !default;
+$padding-base-horizontal:   12px !default;
+
+$padding-large-vertical:    14px !default;
+$padding-large-horizontal:  16px !default;
+
+$padding-small-vertical:    5px !default;
+$padding-small-horizontal:  10px !default;
+
+$padding-xs-vertical:       1px !default;
+$padding-xs-horizontal:     5px !default;
+
+$line-height-large:         1.3333333 !default; // extra decimals for Win 8.1 Chrome
+$line-height-small:         1.5 !default;
+
+$border-radius-base:        4px !default;
+$border-radius-large:       6px !default;
+$border-radius-small:       3px !default;
+
+//** Global color for active items (e.g., navs or dropdowns).
+$component-active-color:    #fff !default;
+//** Global background color for active items (e.g., navs or dropdowns).
+$component-active-bg:       $brand-primary !default;
+
+//** Width of the `border` for generating carets that indicate dropdowns.
+$caret-width-base:          4px !default;
+//** Carets increase slightly in size for larger components.
+$caret-width-large:         5px !default;
+
+
+//== Tables
+//
+//## Customizes the `.table` component with basic values, each used across all table variations.
+
+//** Padding for ``s and ``s.
+$table-cell-padding:            8px !default;
+//** Padding for cells in `.table-condensed`.
+$table-condensed-cell-padding:  5px !default;
+
+//** Default background color used for all tables.
+$table-bg:                      transparent !default;
+//** Background color used for `.table-striped`.
+$table-bg-accent:               #f9f9f9 !default;
+//** Background color used for `.table-hover`.
+$table-bg-hover:                #f5f5f5 !default;
+$table-bg-active:               $table-bg-hover !default;
+
+//** Border color for table and cell borders.
+$table-border-color:            #ddd !default;
+
+
+//== Buttons
+//
+//## For each of Bootstrap's buttons, define text, background and border color.
+
+$btn-font-weight:                normal !default;
+
+$btn-default-color:              $text-color !default;
+$btn-default-bg:                 #fff !default;
+$btn-default-border:             rgba(0, 0, 0, 0.1) !default;
+
+$btn-primary-color:              #fff !default;
+$btn-primary-bg:                 $brand-primary !default;
+$btn-primary-border:             $btn-primary-bg !default;
+
+$btn-success-color:              #fff !default;
+$btn-success-bg:                 $brand-success !default;
+$btn-success-border:             $btn-success-bg !default;
+
+$btn-info-color:                 #fff !default;
+$btn-info-bg:                    $brand-info !default;
+$btn-info-border:                $btn-info-bg !default;
+
+$btn-warning-color:              #fff !default;
+$btn-warning-bg:                 $brand-warning !default;
+$btn-warning-border:             $btn-warning-bg !default;
+
+$btn-danger-color:               #fff !default;
+$btn-danger-bg:                  $brand-danger !default;
+$btn-danger-border:              $btn-danger-bg !default;
+
+$btn-link-disabled-color:        $gray-light !default;
+
+// Allows for customizing button radius independently from global border radius
+$btn-border-radius-base:         $border-radius-base !default;
+$btn-border-radius-large:        $border-radius-large !default;
+$btn-border-radius-small:        $border-radius-small !default;
+
+
+//== Forms
+//
+//##
+
+//** `` background color
+$input-bg:                       #fff !default;
+//** `` background color
+$input-bg-disabled:              $gray-lighter !default;
+
+//** Text color for ``s
+$input-color:                    $text-color !default;
+//** `` border color
+$input-border:                   #ccc !default;
+
+// TODO: Rename `$input-border-radius` to `$input-border-radius-base` in v4
+//** Default `.form-control` border radius
+// This has no effect on ``s in CSS.
+$input-border-radius:            $border-radius-base !default;
+//** Large `.form-control` border radius
+$input-border-radius-large:      $border-radius-large !default;
+//** Small `.form-control` border radius
+$input-border-radius-small:      $border-radius-small !default;
+
+//** Border color for inputs on focus
+$input-border-focus:             #66afe9 !default;
+
+//** Placeholder text color
+$input-color-placeholder:        $gray-light !default;
+
+//** Default `.form-control` height
+$input-height-base:              ($line-height-computed + ($padding-base-vertical * 2) + 2) !default;
+//** Large `.form-control` height
+$input-height-large:             (ceil($font-size-large * $line-height-large) + ($padding-large-vertical * 2) + 2) !default;
+//** Small `.form-control` height
+$input-height-small:             (floor($font-size-small * $line-height-small) + ($padding-small-vertical * 2) + 2) !default;
+
+//** `.form-group` margin
+$form-group-margin-bottom:       15px !default;
+
+$legend-color:                   $text-color !default;
+$legend-border-color:            #e5e5e5 !default;
+
+//** Background color for textual input addons
+$input-group-addon-bg:           $gray-lighter !default;
+//** Border color for textual input addons
+$input-group-addon-border-color: $input-border !default;
+
+//** Disabled cursor for form controls and buttons.
+$cursor-disabled:                not-allowed !default;
+
+
+//== Dropdowns
+//
+//## Dropdown menu container and contents.
+
+//** Background for the dropdown menu.
+$dropdown-bg:                    #fff !default;
+//** Dropdown menu `border-color`.
+$dropdown-border:                rgba(0,0,0,.15) !default;
+//** Dropdown menu `border-color` **for IE8**.
+$dropdown-fallback-border:       #ccc !default;
+//** Divider color for between dropdown items.
+$dropdown-divider-bg:            #e5e5e5 !default;
+
+//** Dropdown link text color.
+$dropdown-link-color:            $gray-dark !default;
+//** Hover color for dropdown links.
+$dropdown-link-hover-color:      #fff !default;
+//** Hover background for dropdown links.
+$dropdown-link-hover-bg:         $component-active-bg !default;
+
+//** Active dropdown menu item text color.
+$dropdown-link-active-color:     #fff !default;
+//** Active dropdown menu item background color.
+$dropdown-link-active-bg:        $component-active-bg !default;
+
+//** Disabled dropdown menu item background color.
+$dropdown-link-disabled-color:   $gray-light !default;
+
+//** Text color for headers within dropdown menus.
+$dropdown-header-color:          $gray-light !default;
+
+//** Deprecated `$dropdown-caret-color` as of v3.1.0
+$dropdown-caret-color:           #000 !default;
+
+
+//-- Z-index master list
+//
+// Warning: Avoid customizing these values. They're used for a bird's eye view
+// of components dependent on the z-axis and are designed to all work together.
+//
+// Note: These variables are not generated into the Customizer.
+
+$zindex-navbar:            1000 !default;
+$zindex-dropdown:          1000 !default;
+$zindex-popover:           1060 !default;
+$zindex-tooltip:           1070 !default;
+$zindex-navbar-fixed:      1030 !default;
+$zindex-modal-background:  1040 !default;
+$zindex-modal:             1050 !default;
+
+
+//== Media queries breakpoints
+//
+//## Define the breakpoints at which your layout will change, adapting to different screen sizes.
+
+// Extra small screen / phone
+//** Deprecated `$screen-xs` as of v3.0.1
+$screen-xs:                  480px !default;
+//** Deprecated `$screen-xs-min` as of v3.2.0
+$screen-xs-min:              $screen-xs !default;
+//** Deprecated `$screen-phone` as of v3.0.1
+$screen-phone:               $screen-xs-min !default;
+
+// Small screen / tablet
+//** Deprecated `$screen-sm` as of v3.0.1
+$screen-sm:                  768px !default;
+$screen-sm-min:              $screen-sm !default;
+//** Deprecated `$screen-tablet` as of v3.0.1
+$screen-tablet:              $screen-sm-min !default;
+
+// Medium screen / desktop
+//** Deprecated `$screen-md` as of v3.0.1
+$screen-md:                  992px !default;
+$screen-md-min:              $screen-md !default;
+//** Deprecated `$screen-desktop` as of v3.0.1
+$screen-desktop:             $screen-md-min !default;
+
+// Large screen / wide desktop
+//** Deprecated `$screen-lg` as of v3.0.1
+$screen-lg:                  1200px !default;
+$screen-lg-min:              $screen-lg !default;
+//** Deprecated `$screen-lg-desktop` as of v3.0.1
+$screen-lg-desktop:          $screen-lg-min !default;
+
+// So media queries don't overlap when required, provide a maximum
+$screen-xs-max:              ($screen-sm-min - 1) !default;
+$screen-sm-max:              ($screen-md-min - 1) !default;
+$screen-md-max:              ($screen-lg-min - 1) !default;
+
+
+//== Grid system
+//
+//## Define your custom responsive grid.
+
+//** Number of columns in the grid.
+$grid-columns:              12 !default;
+//** Padding between columns. Gets divided in half for the left and right.
+$grid-gutter-width:         30px !default;
+// Navbar collapse
+//** Point at which the navbar becomes uncollapsed.
+$grid-float-breakpoint:     $screen-sm-min !default;
+//** Point at which the navbar begins collapsing.
+$grid-float-breakpoint-max: ($grid-float-breakpoint - 1) !default;
+
+
+//== Container sizes
+//
+//## Define the maximum width of `.container` for different screen sizes.
+
+// Small screen / tablet
+$container-tablet:             (720px + $grid-gutter-width) !default;
+//** For `$screen-sm-min` and up.
+$container-sm:                 $container-tablet !default;
+
+// Medium screen / desktop
+$container-desktop:            (940px + $grid-gutter-width) !default;
+//** For `$screen-md-min` and up.
+$container-md:                 $container-desktop !default;
+
+// Large screen / wide desktop
+$container-large-desktop:      (1140px + $grid-gutter-width) !default;
+//** For `$screen-lg-min` and up.
+$container-lg:                 $container-large-desktop !default;
+
+
+//== Navbar
+//
+//##
+
+// Basics of a navbar
+$navbar-height:                    50px !default;
+$navbar-margin-bottom:             $line-height-computed !default;
+$navbar-border-radius:             $border-radius-base !default;
+$navbar-padding-horizontal:        floor(($grid-gutter-width / 2)) !default;
+$navbar-padding-vertical:          (($navbar-height - $line-height-computed) / 2) !default;
+$navbar-collapse-max-height:       340px !default;
+
+$navbar-default-color:             #ddd !default;
+$navbar-default-bg:                $brand-primary !default;
+$navbar-default-border:            darken($navbar-default-bg, 6.5%) !default;
+
+// Navbar links
+$navbar-default-link-color:                #fff !default;
+$navbar-default-link-hover-color:          #fff !default;
+$navbar-default-link-hover-bg:             darken($navbar-default-bg, 10%) !default;
+$navbar-default-link-active-color:         #fff !default;
+$navbar-default-link-active-bg:            darken($navbar-default-bg, 10%) !default;
+$navbar-default-link-disabled-color:       #ddd !default;
+$navbar-default-link-disabled-bg:          transparent !default;
+
+// Navbar brand label
+$navbar-default-brand-color:               $navbar-default-link-color !default;
+$navbar-default-brand-hover-color:         #fff !default;
+$navbar-default-brand-hover-bg:            none !default;
+
+// Navbar toggle
+$navbar-default-toggle-hover-bg:           darken($navbar-default-bg, 10%) !default;
+$navbar-default-toggle-icon-bar-bg:        #fff !default;
+$navbar-default-toggle-border-color:       darken($navbar-default-bg, 10%) !default;
+
+
+//=== Inverted navbar
+// Reset inverted navbar basics
+$navbar-inverse-color:                      #fff !default;
+$navbar-inverse-bg:                         $brand-info !default;
+$navbar-inverse-border:                     darken($navbar-inverse-bg, 5%) !default;
+
+// Inverted navbar links
+$navbar-inverse-link-color:                 #fff !default;
+$navbar-inverse-link-hover-color:           #fff !default;
+$navbar-inverse-link-hover-bg:              darken($navbar-inverse-bg, 5%) !default;
+$navbar-inverse-link-active-color:          #fff !default;
+$navbar-inverse-link-active-bg:             darken($navbar-inverse-bg, 5%) !default;
+$navbar-inverse-link-disabled-color:        #ccc !default;
+$navbar-inverse-link-disabled-bg:           transparent !default;
+
+// Inverted navbar brand label
+$navbar-inverse-brand-color:                $navbar-inverse-link-color !default;
+$navbar-inverse-brand-hover-color:          #fff !default;
+$navbar-inverse-brand-hover-bg:             none !default;
+
+// Inverted navbar toggle
+$navbar-inverse-toggle-hover-bg:            darken($navbar-inverse-bg, 5%) !default;
+$navbar-inverse-toggle-icon-bar-bg:         #fff !default;
+$navbar-inverse-toggle-border-color:        darken($navbar-inverse-bg, 5%) !default;
+
+
+//== Navs
+//
+//##
+
+//=== Shared nav styles
+$nav-link-padding:                          10px 15px !default;
+$nav-link-hover-bg:                         $gray-lighter !default;
+
+$nav-disabled-link-color:                   $gray-light !default;
+$nav-disabled-link-hover-color:             $gray-light !default;
+
+//== Tabs
+$nav-tabs-border-color:                     #ddd !default;
+
+$nav-tabs-link-hover-border-color:          $gray-lighter !default;
+
+$nav-tabs-active-link-hover-bg:             $body-bg !default;
+$nav-tabs-active-link-hover-color:          $gray !default;
+$nav-tabs-active-link-hover-border-color:   #ddd !default;
+
+$nav-tabs-justified-link-border-color:            #ddd !default;
+$nav-tabs-justified-active-link-border-color:     $body-bg !default;
+
+//== Pills
+$nav-pills-border-radius:                   $border-radius-base !default;
+$nav-pills-active-link-hover-bg:            $component-active-bg !default;
+$nav-pills-active-link-hover-color:         $component-active-color !default;
+
+
+//== Pagination
+//
+//##
+
+$pagination-color:                     $link-color !default;
+$pagination-bg:                        #fff !default;
+$pagination-border:                    #ddd !default;
+
+$pagination-hover-color:               $link-hover-color !default;
+$pagination-hover-bg:                  $gray-lighter !default;
+$pagination-hover-border:              #ddd !default;
+
+$pagination-active-color:              $gray-light !default;
+$pagination-active-bg:                 #f5f5f5 !default;
+$pagination-active-border:             $pagination-hover-border !default;
+
+$pagination-disabled-color:            $gray-light !default;
+$pagination-disabled-bg:               #fff !default;
+$pagination-disabled-border:           #ddd !default;
+
+
+//== Pager
+//
+//##
+
+$pager-bg:                             $pagination-bg !default;
+$pager-border:                         $pagination-border !default;
+$pager-border-radius:                  15px !default;
+
+$pager-hover-bg:                       $pagination-hover-bg !default;
+
+$pager-active-bg:                      $pagination-active-bg !default;
+$pager-active-color:                   $pagination-active-color !default;
+
+$pager-disabled-color:                 $gray-light !default;
+
+
+//== Jumbotron
+//
+//##
+
+$jumbotron-padding:              30px !default;
+$jumbotron-color:                inherit !default;
+$jumbotron-bg:                   $gray-lighter !default;
+$jumbotron-heading-color:        inherit !default;
+$jumbotron-font-size:            ceil(($font-size-base * 1.5)) !default;
+$jumbotron-heading-font-size:    ceil(($font-size-base * 4.5)) !default;
+
+
+//== Form states and alerts
+//
+//## Define colors for form feedback states and, by default, alerts.
+
+$state-success-text:             #468847 !default;
+$state-success-bg:               #dff0d8 !default;
+$state-success-border:           darken(adjust-hue($state-success-bg, -10), 5%) !default;
+
+$state-info-text:                #3a87ad !default;
+$state-info-bg:                  #d9edf7 !default;
+$state-info-border:              darken(adjust-hue($state-info-bg, -10), 7%) !default;
+
+$state-warning-text:             #c09853 !default;
+$state-warning-bg:               #fcf8e3 !default;
+$state-warning-border:           darken(adjust-hue($state-warning-bg, -10), 3%) !default;
+
+$state-danger-text:              #b94a48 !default;
+$state-danger-bg:                #f2dede !default;
+$state-danger-border:            darken(adjust-hue($state-danger-bg, -10), 3%) !default;
+
+
+//== Tooltips
+//
+//##
+
+//** Tooltip max width
+$tooltip-max-width:           200px !default;
+//** Tooltip text color
+$tooltip-color:               #fff !default;
+//** Tooltip background color
+$tooltip-bg:                  #000 !default;
+$tooltip-opacity:             .9 !default;
+
+//** Tooltip arrow width
+$tooltip-arrow-width:         5px !default;
+//** Tooltip arrow color
+$tooltip-arrow-color:         $tooltip-bg !default;
+
+
+//== Popovers
+//
+//##
+
+//** Popover body background color
+$popover-bg:                          #fff !default;
+//** Popover maximum width
+$popover-max-width:                   276px !default;
+//** Popover border color
+$popover-border-color:                rgba(0,0,0,.2) !default;
+//** Popover fallback border color
+$popover-fallback-border-color:       #ccc !default;
+
+//** Popover title background color
+$popover-title-bg:                    darken($popover-bg, 3%) !default;
+
+//** Popover arrow width
+$popover-arrow-width:                 10px !default;
+//** Popover arrow color
+$popover-arrow-color:                 $popover-bg !default;
+
+//** Popover outer arrow width
+$popover-arrow-outer-width:           ($popover-arrow-width + 1) !default;
+//** Popover outer arrow color
+$popover-arrow-outer-color:           fadein($popover-border-color, 5%) !default;
+//** Popover outer arrow fallback color
+$popover-arrow-outer-fallback-color:  darken($popover-fallback-border-color, 20%) !default;
+
+
+//== Labels
+//
+//##
+
+//** Default label background color
+$label-default-bg:            $gray-light !default;
+//** Primary label background color
+$label-primary-bg:            $brand-primary !default;
+//** Success label background color
+$label-success-bg:            $brand-success !default;
+//** Info label background color
+$label-info-bg:               $brand-info !default;
+//** Warning label background color
+$label-warning-bg:            $brand-warning !default;
+//** Danger label background color
+$label-danger-bg:             $brand-danger !default;
+
+//** Default label text color
+$label-color:                 #fff !default;
+//** Default text color of a linked label
+$label-link-hover-color:      #fff !default;
+
+
+//== Modals
+//
+//##
+
+//** Padding applied to the modal body
+$modal-inner-padding:         20px !default;
+
+//** Padding applied to the modal title
+$modal-title-padding:         15px !default;
+//** Modal title line-height
+$modal-title-line-height:     $line-height-base !default;
+
+//** Background color of modal content area
+$modal-content-bg:                             #fff !default;
+//** Modal content border color
+$modal-content-border-color:                   rgba(0,0,0,.2) !default;
+//** Modal content border color **for IE8**
+$modal-content-fallback-border-color:          #999 !default;
+
+//** Modal backdrop background color
+$modal-backdrop-bg:           #000 !default;
+//** Modal backdrop opacity
+$modal-backdrop-opacity:      .5 !default;
+//** Modal header border color
+$modal-header-border-color:   #e5e5e5 !default;
+//** Modal footer border color
+$modal-footer-border-color:   $modal-header-border-color !default;
+
+$modal-lg:                    900px !default;
+$modal-md:                    600px !default;
+$modal-sm:                    300px !default;
+
+
+//== Alerts
+//
+//## Define alert colors, border radius, and padding.
+
+$alert-padding:               15px !default;
+$alert-border-radius:         $border-radius-base !default;
+$alert-link-font-weight:      bold !default;
+
+$alert-success-bg:            $state-success-bg !default;
+$alert-success-text:          $state-success-text !default;
+$alert-success-border:        $state-success-border !default;
+
+$alert-info-bg:               $state-info-bg !default;
+$alert-info-text:             $state-info-text !default;
+$alert-info-border:           $state-info-border !default;
+
+$alert-warning-bg:            $state-warning-bg !default;
+$alert-warning-text:          $state-warning-text !default;
+$alert-warning-border:        $state-warning-border !default;
+
+$alert-danger-bg:             $state-danger-bg !default;
+$alert-danger-text:           $state-danger-text !default;
+$alert-danger-border:         $state-danger-border !default;
+
+
+//== Progress bars
+//
+//##
+
+//** Background color of the whole progress component
+$progress-bg:                 #f5f5f5 !default;
+//** Progress bar text color
+$progress-bar-color:          #fff !default;
+//** Variable for setting rounded corners on progress bar.
+$progress-border-radius:      $border-radius-base !default;
+
+//** Default progress bar color
+$progress-bar-bg:             $brand-primary !default;
+//** Success progress bar color
+$progress-bar-success-bg:     $brand-success !default;
+//** Warning progress bar color
+$progress-bar-warning-bg:     $brand-warning !default;
+//** Danger progress bar color
+$progress-bar-danger-bg:      $brand-danger !default;
+//** Info progress bar color
+$progress-bar-info-bg:        $brand-info !default;
+
+
+//== List group
+//
+//##
+
+//** Background color on `.list-group-item`
+$list-group-bg:                 #fff !default;
+//** `.list-group-item` border color
+$list-group-border:             #ddd !default;
+//** List group border radius
+$list-group-border-radius:      $border-radius-base !default;
+
+//** Background color of single list items on hover
+$list-group-hover-bg:           #f5f5f5 !default;
+//** Text color of active list items
+$list-group-active-color:       $component-active-color !default;
+//** Background color of active list items
+$list-group-active-bg:          $component-active-bg !default;
+//** Border color of active list elements
+$list-group-active-border:      $list-group-active-bg !default;
+//** Text color for content within active list items
+$list-group-active-text-color:  lighten($list-group-active-bg, 40%) !default;
+
+//** Text color of disabled list items
+$list-group-disabled-color:      $gray-light !default;
+//** Background color of disabled list items
+$list-group-disabled-bg:         $gray-lighter !default;
+//** Text color for content within disabled list items
+$list-group-disabled-text-color: $list-group-disabled-color !default;
+
+$list-group-link-color:         #555 !default;
+$list-group-link-hover-color:   $list-group-link-color !default;
+$list-group-link-heading-color: #333 !default;
+
+
+//== Panels
+//
+//##
+
+$panel-bg:                    #fff !default;
+$panel-body-padding:          15px !default;
+$panel-heading-padding:       10px 15px !default;
+$panel-footer-padding:        $panel-heading-padding !default;
+$panel-border-radius:         $border-radius-base !default;
+
+//** Border color for elements within panels
+$panel-inner-border:          #ddd !default;
+$panel-footer-bg:             #f5f5f5 !default;
+
+$panel-default-text:          $text-color !default;
+$panel-default-border:        #ddd !default;
+$panel-default-heading-bg:    #f5f5f5 !default;
+
+$panel-primary-text:          #fff !default;
+$panel-primary-border:        $panel-default-border !default;
+$panel-primary-heading-bg:    $brand-primary !default;
+
+$panel-success-text:          $state-success-text !default;
+$panel-success-border:        $panel-default-border !default;
+$panel-success-heading-bg:    $brand-success !default;
+
+$panel-info-text:             $state-info-text !default;
+$panel-info-border:           $panel-default-border !default;
+$panel-info-heading-bg:       $brand-info !default;
+
+$panel-warning-text:          $state-warning-text !default;
+$panel-warning-border:        $panel-default-border !default;
+$panel-warning-heading-bg:    $brand-warning !default;
+
+$panel-danger-text:           $state-danger-text !default;
+$panel-danger-border:         $panel-default-border !default;
+$panel-danger-heading-bg:     $brand-danger !default;
+
+
+//== Thumbnails
+//
+//##
+
+//** Padding around the thumbnail image
+$thumbnail-padding:           4px !default;
+//** Thumbnail background color
+$thumbnail-bg:                $body-bg !default;
+//** Thumbnail border color
+$thumbnail-border:            #ddd !default;
+//** Thumbnail border radius
+$thumbnail-border-radius:     $border-radius-base !default;
+
+//** Custom text color for thumbnail captions
+$thumbnail-caption-color:     $text-color !default;
+//** Padding around the thumbnail caption
+$thumbnail-caption-padding:   9px !default;
+
+
+//== Wells
+//
+//##
+
+$well-bg:                     #f5f5f5 !default;
+$well-border:                 darken($well-bg, 7%) !default;
+
+
+//== Badges
+//
+//##
+
+$badge-color:                 #fff !default;
+//** Linked badge text color on hover
+$badge-link-hover-color:      #fff !default;
+$badge-bg:                    $brand-primary !default;
+
+//** Badge text color in active nav link
+$badge-active-color:          $link-color !default;
+//** Badge background color in active nav link
+$badge-active-bg:             #fff !default;
+
+$badge-font-weight:           bold !default;
+$badge-line-height:           1 !default;
+$badge-border-radius:         10px !default;
+
+
+//== Breadcrumbs
+//
+//##
+
+$breadcrumb-padding-vertical:   8px !default;
+$breadcrumb-padding-horizontal: 15px !default;
+//** Breadcrumb background color
+$breadcrumb-bg:                 #f5f5f5 !default;
+//** Breadcrumb text color
+$breadcrumb-color:              #ccc !default;
+//** Text color of current page in the breadcrumb
+$breadcrumb-active-color:       $gray-light !default;
+//** Textual separator for between breadcrumb elements
+$breadcrumb-separator:          "/" !default;
+
+
+//== Carousel
+//
+//##
+
+$carousel-text-shadow:                        0 1px 2px rgba(0,0,0,.6) !default;
+
+$carousel-control-color:                      #fff !default;
+$carousel-control-width:                      15% !default;
+$carousel-control-opacity:                    .5 !default;
+$carousel-control-font-size:                  20px !default;
+
+$carousel-indicator-active-bg:                #fff !default;
+$carousel-indicator-border-color:             #fff !default;
+
+$carousel-caption-color:                      #fff !default;
+
+
+//== Close
+//
+//##
+
+$close-font-weight:           bold !default;
+$close-color:                 #000 !default;
+$close-text-shadow:           0 1px 0 #fff !default;
+
+
+//== Code
+//
+//##
+
+$code-color:                  #c7254e !default;
+$code-bg:                     #f9f2f4 !default;
+
+$kbd-color:                   #fff !default;
+$kbd-bg:                      #333 !default;
+
+$pre-bg:                      #f5f5f5 !default;
+$pre-color:                   $gray-dark !default;
+$pre-border-color:            #ccc !default;
+$pre-scrollable-max-height:   340px !default;
+
+
+//== Type
+//
+//##
+
+//** Horizontal offset for forms and lists.
+$component-offset-horizontal: 180px !default;
+//** Text muted color
+$text-muted:                  $gray-light !default;
+//** Abbreviations and acronyms border color
+$abbr-border-color:           $gray-light !default;
+//** Headings small color
+$headings-small-color:        $gray-light !default;
+//** Blockquote small color
+$blockquote-small-color:      $gray-light !default;
+//** Blockquote font size
+$blockquote-font-size:        ($font-size-base * 1.25) !default;
+//** Blockquote border color
+$blockquote-border-color:     $gray-lighter !default;
+//** Page header border color
+$page-header-border-color:    $gray-lighter !default;
+//** Width of horizontal description list titles
+$dl-horizontal-offset:        $component-offset-horizontal !default;
+//** Point at which .dl-horizontal becomes horizontal
+$dl-horizontal-breakpoint:    $grid-float-breakpoint !default;
+//** Horizontal line color.
+$hr-border:                   $gray-lighter !default;
diff --git a/lib/collections/documents.js b/lib/collections/documents.js
deleted file mode 100755
index f77a332..0000000
--- a/lib/collections/documents.js
+++ /dev/null
@@ -1,100 +0,0 @@
-// ***************************************************************
-// DOCUMENTS COLLECTION
-// ***************************************************************
-
-Documents = new Mongo.Collection('documents');
-
-DocumentSchema = new SimpleSchema({
-  title: {
-    type: String,
-    label: "Title",
-    max: 120,
-    optional: false
-  },
-  content: {
-    type: String,
-    label: "Content",
-    max: 1000,
-    optional: true
-  },
-  createdAt: {
-    type: Date,
-    optional: true,
-    denyUpdate: true,
-    autoValue: function() {
-      if (this.isInsert) {
-        return new Date();
-      }
-    }
-  },
-  updatedAt: {
-    type: Date,
-    optional: true,
-    denyInsert: true,
-    autoValue: function() {
-      if (this.isUpdate) {
-        return new Date();
-      }
-    }
-  }
-});
-
-// Must remember to attach the schema to the collection
-Documents.attachSchema(DocumentSchema);
-
-// Custom validation messages with SimpleSchema. Remove if not needed
-Documents.simpleSchema().messages({
-  required: "[label] is required",
-  minString: "[label] must be at least [min] characters",
-  maxString: "[label] cannot exceed [max] characters",
-  minNumber: "[label] must be at least [min]",
-  maxNumber: "[label] cannot exceed [max]",
-  minDate: "[label] must be on or before [min]",
-  maxDate: "[label] cannot be after [max]",
-  minCount: "You must specify at least [minCount] values",
-  maxCount: "You cannot specify more than [maxCount] values",
-  noDecimal: "[label] must be an integer",
-  notAllowed: "[value] is not an allowed value",
-  expectedString: "[label] must be a string",
-  expectedNumber: "[label] must be a number",
-  expectedBoolean: "[label] must be a boolean",
-  expectedArray: "[label] must be an array",
-  expectedObject: "[label] must be an object",
-  expectedConstructor: "[label] must be a [type]",
-  regEx: [
-  {msg: "[label] failed regular expression validation"},
-  {exp: SimpleSchema.RegEx.Email, msg: "[label] must be a valid e-mail address"},
-  {exp: SimpleSchema.RegEx.WeakEmail, msg: "[label] must be a valid e-mail address"},
-  {exp: SimpleSchema.RegEx.Domain, msg: "[label] must be a valid domain"},
-  {exp: SimpleSchema.RegEx.WeakDomain, msg: "[label] must be a valid domain"},
-  {exp: SimpleSchema.RegEx.IP, msg: "[label] must be a valid IPv4 or IPv6 address"},
-  {exp: SimpleSchema.RegEx.IPv4, msg: "[label] must be a valid IPv4 address"},
-  {exp: SimpleSchema.RegEx.IPv6, msg: "[label] must be a valid IPv6 address"},
-  {exp: SimpleSchema.RegEx.Url, msg: "[label] must be a valid URL"},
-  {exp: SimpleSchema.RegEx.Id, msg: "[label] must be a valid alphanumeric ID"}
-  ],
-  keyNotInSchema: "[label] is not allowed by the schema"
-});
-
-// Allow and deny rules
-Documents.allow({
-  insert: function (userId, doc) {
-    // Free-for-all!
-    return true;
-  },
-  update: function (userId, doc, fields, modifier) {
-    // Free-for-all!
-    return true;
-  },
-  remove: function (userId, doc) {
-    // Free-for-all!
-    return true;
-  }
-});
-
-// Meteor methods related to collection
-Meteor.methods({
-  someMethod: function(arg1, arg2) {
-    return "some return value";
-  },
-});
diff --git a/lib/helpers/helpers.js b/lib/helpers/helpers.js
deleted file mode 100755
index 1d960bc..0000000
--- a/lib/helpers/helpers.js
+++ /dev/null
@@ -1,3 +0,0 @@
-// ***************************************************************
-// COMMON HELPERS (shared with client and server)
-// ***************************************************************
diff --git a/lib/helpers/permissions.js b/lib/helpers/permissions.js
deleted file mode 100755
index 4ec45df..0000000
--- a/lib/helpers/permissions.js
+++ /dev/null
@@ -1,19 +0,0 @@
-// ***************************************************************
-// PERMISSIONS (shared with client and server)
-// ***************************************************************
-
-// If the user owns the item, give permission
-canEditItem = function (userId, item) {
-  return userId === item.userId;
-}
-
-// If the user owns the item, give permission
-canRemoveItem = function (userId, item) {
-  return userId === item.userId;
-}
-
-// Checks whether selected user or current user is admin (with the Roles package)
-isAdmin = function (user) {
-  user = (typeof user === 'undefined') ? Meteor.user() : user;
-  return !!user && !!Roles.userIsInRole(user, ['admin']);
-}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..2ea63d2
--- /dev/null
+++ b/package.json
@@ -0,0 +1,13 @@
+{
+  "name": "meteor-skeleton",
+  "private": true,
+  "scripts": {
+    "start": "meteor run"
+  },
+  "dependencies": {
+    "babel-runtime": "^6.18.0",
+    "bootstrap-sass": "^3.3.7",
+    "meteor-node-stubs": "~0.2.0",
+    "moment": "^2.15.2"
+  }
+}
diff --git a/public/android-chrome-144x144.png b/public/android-chrome-144x144.png
new file mode 100644
index 0000000..282978e
Binary files /dev/null and b/public/android-chrome-144x144.png differ
diff --git a/public/apple-touch-icon.png b/public/apple-touch-icon.png
new file mode 100644
index 0000000..69a9f28
Binary files /dev/null and b/public/apple-touch-icon.png differ
diff --git a/public/browserconfig.xml b/public/browserconfig.xml
new file mode 100644
index 0000000..29c6ff5
--- /dev/null
+++ b/public/browserconfig.xml
@@ -0,0 +1,9 @@
+
+
+  
+    
+      
+      #2b5797
+    
+  
+
diff --git a/public/favicon-16x16.png b/public/favicon-16x16.png
new file mode 100644
index 0000000..553ac5b
Binary files /dev/null and b/public/favicon-16x16.png differ
diff --git a/public/favicon-32x32.png b/public/favicon-32x32.png
new file mode 100644
index 0000000..0318901
Binary files /dev/null and b/public/favicon-32x32.png differ
diff --git a/public/favicon.ico b/public/favicon.ico
new file mode 100644
index 0000000..c2dc3d1
Binary files /dev/null and b/public/favicon.ico differ
diff --git a/.meteor/cordova-plugins b/public/fonts/.gitkeep
old mode 100755
new mode 100644
similarity index 100%
rename from .meteor/cordova-plugins
rename to public/fonts/.gitkeep
diff --git a/public/fonts/glyphicons-halflings-regular.eot b/public/fonts/glyphicons-halflings-regular.eot
deleted file mode 100755
index 4a4ca86..0000000
Binary files a/public/fonts/glyphicons-halflings-regular.eot and /dev/null differ
diff --git a/public/fonts/glyphicons-halflings-regular.svg b/public/fonts/glyphicons-halflings-regular.svg
deleted file mode 100755
index e3e2dc7..0000000
--- a/public/fonts/glyphicons-halflings-regular.svg
+++ /dev/null
@@ -1,229 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 
\ No newline at end of file
diff --git a/public/fonts/glyphicons-halflings-regular.ttf b/public/fonts/glyphicons-halflings-regular.ttf
deleted file mode 100755
index 67fa00b..0000000
Binary files a/public/fonts/glyphicons-halflings-regular.ttf and /dev/null differ
diff --git a/public/fonts/glyphicons-halflings-regular.woff b/public/fonts/glyphicons-halflings-regular.woff
deleted file mode 100755
index 8c54182..0000000
Binary files a/public/fonts/glyphicons-halflings-regular.woff and /dev/null differ
diff --git a/client/views/main.js b/public/img/.gitkeep
old mode 100755
new mode 100644
similarity index 100%
rename from client/views/main.js
rename to public/img/.gitkeep
diff --git a/public/manifest.json b/public/manifest.json
new file mode 100644
index 0000000..1a00851
--- /dev/null
+++ b/public/manifest.json
@@ -0,0 +1,12 @@
+{
+	"name": "Meteor-skeleton",
+	"icons": [
+		{
+			"src": "\/android-chrome-144x144.png",
+			"sizes": "144x144",
+			"type": "image\/png"
+		}
+	],
+	"theme_color": "#ff0000",
+	"display": "standalone"
+}
diff --git a/public/mstile-150x150.png b/public/mstile-150x150.png
new file mode 100644
index 0000000..3f93f52
Binary files /dev/null and b/public/mstile-150x150.png differ
diff --git a/public/safari-pinned-tab.svg b/public/safari-pinned-tab.svg
new file mode 100644
index 0000000..196f2ee
--- /dev/null
+++ b/public/safari-pinned-tab.svg
@@ -0,0 +1,43 @@
+
+
+
+
+Created by potrace 1.11, written by Peter Selinger 2001-2013
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/server/config/accounts.js b/server/config/accounts.js
deleted file mode 100755
index e28e956..0000000
--- a/server/config/accounts.js
+++ /dev/null
@@ -1,3 +0,0 @@
-// ***************************************************************
-// ACCOUNTS CONFIGURATION (server-side)
-// ***************************************************************
diff --git a/server/main.js b/server/main.js
new file mode 100644
index 0000000..3159f3c
--- /dev/null
+++ b/server/main.js
@@ -0,0 +1,2 @@
+import '/imports/startup/server/_main.js';
+import '/imports/startup/both/_main.js';
diff --git a/server/publications/documents.js b/server/publications/documents.js
deleted file mode 100755
index 4b20d98..0000000
--- a/server/publications/documents.js
+++ /dev/null
@@ -1,15 +0,0 @@
-// ***************************************************************
-// PUBLICATIONS (For Documents collection)
-// ***************************************************************
-
-// DOCUMENTS INDEX
-// -------------------------------------------------------
-Meteor.publish('documents', function() {
-  return Documents.find();
-});
-
-// DOCUMENT SHOW
-// -------------------------------------------------------
-Meteor.publish('document', function(id) {
-  return Documents.find(id);
-});
\ No newline at end of file