Repository: pbernasconi/ionic-theme-editor Branch: master Commit: 558f51695574 Files: 171 Total size: 1.2 MB Directory structure: gitextract_mcss25s2/ ├── .bowerrc ├── .buildignore ├── .gitignore ├── .travis.yml ├── .yo-rc.json ├── Gruntfile.js ├── LICENSE.md ├── README.md ├── bower.json ├── client/ │ ├── .htaccess │ ├── .jshintrc │ ├── app/ │ │ ├── app.css │ │ ├── app.js │ │ ├── compiler/ │ │ │ ├── compiler.service.js │ │ │ └── compiler.service.spec.js │ │ ├── main/ │ │ │ ├── main.controller.js │ │ │ ├── main.controller.spec.js │ │ │ ├── main.css │ │ │ ├── main.html │ │ │ └── main.js │ │ └── theme/ │ │ ├── theme.directive.js │ │ └── theme.directive.spec.js │ ├── components/ │ │ └── preview/ │ │ ├── preview-buttons.html │ │ ├── preview-card.html │ │ ├── preview-components.html │ │ ├── preview-form.html │ │ ├── preview-header.html │ │ ├── preview-list.html │ │ └── preview-tabs.html │ ├── index.html │ └── robots.txt ├── e2e/ │ └── main/ │ ├── main.po.js │ └── main.spec.js ├── ionic-tailor.sketch ├── karma.conf.js ├── package.json ├── protractor.conf.js └── server/ ├── .jshintrc ├── api/ │ ├── compile/ │ │ ├── compile.controller.js │ │ ├── compile.model.js │ │ ├── compile.spec.js │ │ └── index.js │ └── themes/ │ ├── index.js │ ├── themes.controller.js │ ├── themes.model.js │ └── themes.spec.js ├── app.js ├── components/ │ └── errors/ │ └── index.js ├── config/ │ ├── environment/ │ │ ├── development.js │ │ ├── index.js │ │ ├── production.js │ │ └── test.js │ └── express.js ├── ionic/ │ ├── scss-live/ │ │ ├── _action-sheet.scss │ │ ├── _animations.scss │ │ ├── _backdrop.scss │ │ ├── _badge.scss │ │ ├── _bar.scss │ │ ├── _button-bar.scss │ │ ├── _button.scss │ │ ├── _checkbox.scss │ │ ├── _form.scss │ │ ├── _grid.scss │ │ ├── _items.scss │ │ ├── _list.scss │ │ ├── _loaders.scss │ │ ├── _loading.scss │ │ ├── _menu.scss │ │ ├── _mixins.scss │ │ ├── _modal.scss │ │ ├── _platform.scss │ │ ├── _popover.scss │ │ ├── _popup.scss │ │ ├── _progress.scss │ │ ├── _radio.scss │ │ ├── _range.scss │ │ ├── _refresher.scss │ │ ├── _reset.scss │ │ ├── _scaffolding.scss │ │ ├── _select.scss │ │ ├── _slide-box.scss │ │ ├── _split-pane.scss │ │ ├── _tabs.scss │ │ ├── _toggle.scss │ │ ├── _transitions.scss │ │ ├── _type.scss │ │ ├── _util.scss │ │ ├── _variables.scss │ │ ├── ionic.scss │ │ └── ionicons/ │ │ ├── _ionicons-animation.scss │ │ ├── _ionicons-font.scss │ │ ├── _ionicons-icons.scss │ │ ├── _ionicons-variables.scss │ │ └── ionicons.scss │ ├── scss-prod/ │ │ ├── _action-sheet.scss │ │ ├── _animations.scss │ │ ├── _backdrop.scss │ │ ├── _badge.scss │ │ ├── _bar.scss │ │ ├── _button-bar.scss │ │ ├── _button.scss │ │ ├── _checkbox.scss │ │ ├── _form.scss │ │ ├── _grid.scss │ │ ├── _items.scss │ │ ├── _list.scss │ │ ├── _loaders.scss │ │ ├── _loading.scss │ │ ├── _menu.scss │ │ ├── _mixins.scss │ │ ├── _modal.scss │ │ ├── _platform.scss │ │ ├── _popover.scss │ │ ├── _popup.scss │ │ ├── _progress.scss │ │ ├── _radio.scss │ │ ├── _range.scss │ │ ├── _refresher.scss │ │ ├── _reset.scss │ │ ├── _scaffolding.scss │ │ ├── _select.scss │ │ ├── _slide-box.scss │ │ ├── _split-pane.scss │ │ ├── _tabs.scss │ │ ├── _toggle.scss │ │ ├── _transitions.scss │ │ ├── _type.scss │ │ ├── _util.scss │ │ ├── _variables.scss │ │ ├── ionic.scss │ │ └── ionicons/ │ │ ├── _ionicons-animation.scss │ │ ├── _ionicons-font.scss │ │ ├── _ionicons-icons.scss │ │ ├── _ionicons-variables.scss │ │ └── ionicons.scss │ ├── scss_test/ │ │ ├── _action-sheet.scss │ │ ├── _animations.scss │ │ ├── _backdrop.scss │ │ ├── _badge.scss │ │ ├── _bar.scss │ │ ├── _button-bar.scss │ │ ├── _button.scss │ │ ├── _checkbox.scss │ │ ├── _form.scss │ │ ├── _grid.scss │ │ ├── _items.scss │ │ ├── _list.scss │ │ ├── _loading.scss │ │ ├── _menu.scss │ │ ├── _mixins.scss │ │ ├── _modal.scss │ │ ├── _platform.scss │ │ ├── _popover.scss │ │ ├── _popup.scss │ │ ├── _progress.scss │ │ ├── _radio.scss │ │ ├── _range.scss │ │ ├── _reset.scss │ │ ├── _scaffolding.scss │ │ ├── _select.scss │ │ ├── _slide-box.scss │ │ ├── _tabs.scss │ │ ├── _toggle.scss │ │ ├── _type.scss │ │ ├── _util.scss │ │ ├── _variables.scss │ │ └── ionic.scss │ └── tmp/ │ ├── ionic-Zk2IRRDU4.app.css │ └── ionic-ZkD6jCwL4.app.css ├── routes.js └── views/ └── 404.html ================================================ FILE CONTENTS ================================================ ================================================ FILE: .bowerrc ================================================ { "directory": "client/bower_components" } ================================================ FILE: .buildignore ================================================ *.coffee ================================================ FILE: .gitignore ================================================ dist node_modules .idea .tmp client/bower_components server/config/local.env.js ================================================ FILE: .travis.yml ================================================ language: node_js node_js: - '0.10' - '0.11' before_script: - npm install -g bower grunt-cli - bower install services: mongodb ================================================ FILE: .yo-rc.json ================================================ { "generator-angular-fullstack": { "insertRoutes": true, "registerRoutesFile": "server/routes.js", "routesNeedle": "// Insert routes below", "routesBase": "/api/", "pluralizeRoutes": true, "insertSockets": true, "registerSocketsFile": "server/config/socketio.js", "socketsNeedle": "// Insert sockets below", "filters": { "js": true, "html": true, "css": true, "uirouter": true, "bootstrap": true, "uibootstrap": true, "mongoose": true } }, "generator-ng-component": { "routeDirectory": "client/app/", "directiveDirectory": "client/app/", "filterDirectory": "client/app/", "serviceDirectory": "client/app/", "basePath": "client", "filters": [ "uirouter" ], "extensions": [ "js", "html", "css" ] } } ================================================ FILE: Gruntfile.js ================================================ 'use strict'; module.exports = function (grunt) { var localConfig; try { localConfig = require('./server/config/local.env'); } catch (e) { localConfig = {}; } // Load grunt tasks automatically, when needed require('jit-grunt')(grunt, { express: 'grunt-express-server', useminPrepare: 'grunt-usemin', ngtemplates: 'grunt-angular-templates', cdnify: 'grunt-google-cdn', protractor: 'grunt-protractor-runner', injector: 'grunt-asset-injector' }); // Time how long tasks take. Can help when optimizing build times require('time-grunt')(grunt); // Define the configuration for all the tasks grunt.initConfig({ // Project settings yeoman: { // configurable paths client: require('./bower.json').appPath || 'client', dist: 'dist' }, express: { options: { port: process.env.PORT || 9000 }, dev: { options: { script: 'server/app.js', debug: true } }, prod: { options: { script: 'dist/server/app.js' } } }, open: { server: { url: 'http://localhost:<%= express.options.port %>' } }, watch: { injectJS: { files: [ '<%= yeoman.client %>/{app,components}/**/*.js', '!<%= yeoman.client %>/{app,components}/**/*.spec.js', '!<%= yeoman.client %>/{app,components}/**/*.mock.js', '!<%= yeoman.client %>/app/app.js'], tasks: ['injector:scripts'] }, injectCss: { files: [ '<%= yeoman.client %>/{app,components}/**/*.css' ], tasks: ['injector:css'] }, mochaTest: { files: ['server/**/*.spec.js'], tasks: ['env:test', 'mochaTest'] }, jsTest: { files: [ '<%= yeoman.client %>/{app,components}/**/*.spec.js', '<%= yeoman.client %>/{app,components}/**/*.mock.js' ], tasks: ['newer:jshint:all', 'karma'] }, gruntfile: { files: ['Gruntfile.js'] }, livereload: { files: [ '{.tmp,<%= yeoman.client %>}/{app,components}/**/*.css', '{.tmp,<%= yeoman.client %>}/{app,components}/**/*.html', '{.tmp,<%= yeoman.client %>}/{app,components}/**/*.js', '!{.tmp,<%= yeoman.client %>}{app,components}/**/*.spec.js', '!{.tmp,<%= yeoman.client %>}/{app,components}/**/*.mock.js', '<%= yeoman.client %>/assets/images/{,*//*}*.{png,jpg,jpeg,gif,webp,svg}' ], options: { livereload: true } }, express: { files: [ 'server/**/*.{js,json}' ], tasks: ['express:dev', 'wait'], options: { livereload: true, nospawn: true //Without this option specified express won't be reloaded } } }, // Make sure code styles are up to par and there are no obvious mistakes jshint: { options: { jshintrc: '<%= yeoman.client %>/.jshintrc', reporter: require('jshint-stylish') }, server: { options: { jshintrc: 'server/.jshintrc' }, src: [ 'server/{,*/}*.js'] }, all: [ '<%= yeoman.client %>/{app,components}/**/*.js', '!<%= yeoman.client %>/{app,components}/**/*.spec.js', '!<%= yeoman.client %>/{app,components}/**/*.mock.js' ], test: { src: [ '<%= yeoman.client %>/{app,components}/**/*.spec.js', '<%= yeoman.client %>/{app,components}/**/*.mock.js' ] } }, // Empties folders to start fresh clean: { dist: { files: [ { dot: true, src: [ '.tmp', '<%= yeoman.dist %>/*', '!<%= yeoman.dist %>/.git*', '!<%= yeoman.dist %>/.openshift', '!<%= yeoman.dist %>/Procfile' ] } ] }, server: '.tmp' }, // Add vendor prefixed styles autoprefixer: { options: { browsers: ['last 1 version'] }, dist: { files: [ { expand: true, cwd: '.tmp/', src: '{,*/}*.css', dest: '.tmp/' } ] } }, // Debugging with node inspector 'node-inspector': { custom: { options: { 'web-host': 'localhost' } } }, // Use nodemon to run server in debug mode with an initial breakpoint nodemon: { debug: { script: 'server/app.js', options: { nodeArgs: ['--debug-brk'], env: { PORT: process.env.PORT || 9000 }, callback: function (nodemon) { nodemon.on('log', function (event) { console.log(event.colour); }); // opens browser on initial server start nodemon.on('config:update', function () { setTimeout(function () { require('open')('http://localhost:8080/debug?port=5858'); }, 500); }); } } } }, // Automatically inject Bower components into the app bowerInstall: { target: { src: '<%= yeoman.client %>/index.html', ignorePath: '<%= yeoman.client %>/', exclude: [/bootstrap-sass-official/, /bootstrap.js/, '/json3/', '/es5-shim/'] } }, // Renames files for browser caching purposes rev: { dist: { files: { src: [ '<%= yeoman.dist %>/public/{,*/}*.js', '<%= yeoman.dist %>/public/{,*/}*.css', '<%= yeoman.dist %>/public/assets/fonts/*' ] } } }, // Reads HTML for usemin blocks to enable smart builds that automatically // concat, minify and revision files. Creates configurations in memory so // additional tasks can operate on them useminPrepare: { html: ['<%= yeoman.client %>/index.html'], options: { dest: '<%= yeoman.dist %>/public' } }, // Performs rewrites based on rev and the useminPrepare configuration usemin: { html: ['<%= yeoman.dist %>/public/{,*/}*.html'], css: ['<%= yeoman.dist %>/public/{,*/}*.css'], js: ['<%= yeoman.dist %>/public/{,*/}*.js'], options: { assetsDirs: [ '<%= yeoman.dist %>/public', '<%= yeoman.dist %>/public/assets/images' ], // This is so we update image references in our ng-templates patterns: { js: [ [/(assets\/images\/.*?\.(?:gif|jpeg|jpg|png|webp|svg))/gm, 'Update the JS to reference our revved images'] ] } } }, // The following *-min tasks produce minified files in the dist folder imagemin: { dist: { files: [ { expand: true, cwd: '<%= yeoman.client %>/assets/images', src: '{,*/}*.{png,jpg,jpeg,gif}', dest: '<%= yeoman.dist %>/public/assets/images' } ] } }, svgmin: { dist: { files: [ { expand: true, cwd: '<%= yeoman.client %>/assets/images', src: '{,*/}*.svg', dest: '<%= yeoman.dist %>/public/assets/images' } ] } }, // Allow the use of non-minsafe AngularJS files. Automatically makes it // minsafe compatible so Uglify does not destroy the ng references ngAnnotate: { dist: { files: [ { expand: true, cwd: '.tmp/concat', src: '*/**.js', dest: '.tmp/concat' } ] } }, // Package all the html partials into a single javascript payload ngtemplates: { options: { // This should be the name of your apps angular module module: 'projectsApp', htmlmin: { collapseBooleanAttributes: true, collapseWhitespace: true, removeAttributeQuotes: true, removeEmptyAttributes: true, removeRedundantAttributes: true, removeScriptTypeAttributes: true, removeStyleLinkTypeAttributes: true }, usemin: 'app/app.js' }, main: { cwd: '<%= yeoman.client %>', src: ['{app,components}/**/*.html'], dest: '.tmp/templates.js' }, tmp: { cwd: '.tmp', src: ['{app,components}/**/*.html'], dest: '.tmp/tmp-templates.js' } }, // Replace Google CDN references cdnify: { dist: { html: ['<%= yeoman.dist %>/*.html'] } }, // Copies remaining files to places other tasks can use copy: { dist: { files: [ { expand: true, dot: true, cwd: '<%= yeoman.client %>', dest: '<%= yeoman.dist %>/public', src: [ '*.{ico,png,txt}', '.htaccess', 'bower_components/**/*', 'assets/images/{,*/}*.{webp}', 'assets/fonts/**/*', 'components/**/*', 'index.html' ] }, { expand: true, cwd: '.tmp/images', dest: '<%= yeoman.dist %>/public/assets/images', src: ['generated/*'] }, { expand: true, dest: '<%= yeoman.dist %>', src: [ 'package.json', 'server/**/*' ] } ] }, styles: { expand: true, cwd: '<%= yeoman.client %>', dest: '.tmp/', src: ['{app,components}/**/*.css'] } }, // Run some tasks in parallel to speed up the build process concurrent: { server: [ ], test: [ ], debug: { tasks: [ 'nodemon', 'node-inspector' ], options: { logConcurrentOutput: true } }, dist: [ 'imagemin', 'svgmin' ] }, // Test settings karma: { unit: { configFile: 'karma.conf.js', singleRun: true } }, mochaTest: { options: { reporter: 'spec' }, src: ['server/**/*.spec.js'] }, protractor: { options: { configFile: 'protractor.conf.js' }, chrome: { options: { args: { browser: 'chrome' } } } }, env: { test: { NODE_ENV: 'test' }, prod: { NODE_ENV: 'production' }, all: localConfig }, injector: { options: { }, // Inject application script files into index.html (doesn't include bower) scripts: { options: { transform: function (filePath) { filePath = filePath.replace('/client/', ''); filePath = filePath.replace('/.tmp/', ''); return ''; }, starttag: '', endtag: '' }, files: { '<%= yeoman.client %>/index.html': [ ['{.tmp,<%= yeoman.client %>}/{app,components}/**/*.js', '!{.tmp,<%= yeoman.client %>}/app/app.js', '!{.tmp,<%= yeoman.client %>}/{app,components}/**/*.spec.js', '!{.tmp,<%= yeoman.client %>}/{app,components}/**/*.mock.js'] ] } }, // Inject component css into index.html css: { options: { transform: function (filePath) { filePath = filePath.replace('/client/', ''); filePath = filePath.replace('/.tmp/', ''); return ''; }, starttag: '', endtag: '' }, files: { '<%= yeoman.client %>/index.html': [ '<%= yeoman.client %>/{app,components}/**/*.css' ] } } } }); // Used for delaying livereload until after server has restarted grunt.registerTask('wait', function () { grunt.log.ok('Waiting for server reload...'); var done = this.async(); setTimeout(function () { grunt.log.writeln('Done waiting!'); done(); }, 1500); }); grunt.registerTask('express-keepalive', 'Keep grunt running', function () { this.async(); }); grunt.registerTask('serve', function (target) { if (target === 'dist') { return grunt.task.run(['build', 'env:all', 'env:prod', 'express:prod', 'wait', 'open', 'express-keepalive']); } if (target === 'debug') { return grunt.task.run([ 'clean:server', 'env:all', 'concurrent:server', 'injector', 'bowerInstall', 'autoprefixer', 'concurrent:debug' ]); } grunt.task.run([ 'clean:server', 'env:all', 'concurrent:server', 'injector', 'bowerInstall', 'autoprefixer', 'express:dev', 'wait', 'open', 'watch' ]); }); grunt.registerTask('server', function () { grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.'); grunt.task.run(['serve']); }); grunt.registerTask('test', function (target) { if (target === 'server') { return grunt.task.run([ 'env:all', 'env:test', 'mochaTest' ]); } else if (target === 'client') { return grunt.task.run([ 'clean:server', 'env:all', 'concurrent:test', 'injector', 'autoprefixer', 'karma' ]); } else if (target === 'e2e') { return grunt.task.run([ 'clean:server', 'env:all', 'env:test', 'concurrent:test', 'injector', 'bowerInstall', 'autoprefixer', 'express:dev', 'protractor' ]); } else grunt.task.run([ 'test:server', 'test:client' ]); }); grunt.registerTask('build', [ 'clean:dist', 'concurrent:dist', 'injector', 'bowerInstall', 'useminPrepare', 'autoprefixer', 'ngtemplates', 'concat', 'ngAnnotate', 'copy:dist', 'cdnify', 'cssmin', 'uglify', 'rev', 'usemin' ]); grunt.registerTask('default', [ 'newer:jshint', 'test', 'build' ]); }; ================================================ FILE: LICENSE.md ================================================ The MIT License (MIT) Copyright (c) 2014 Paolo Bernasconi 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. ================================================ FILE: README.md ================================================ [Ionic Theme Editor](http://ionic-theme-editor.herokuapp.com/) ================== [![preview](https://github.com/pbernasconi/ionic-theme-editor/blob/master/Ionic-Theme-Editor.png)](http://ionic-theme-editor.herokuapp.com/) ## Website [http://ionic-theme-editor.herokuapp.com/](http://ionic-theme-editor.herokuapp.com/) ## About The Ionic Theme Editor is a simple live-editor for the [Ionic Framework](ionicframework.com). You can visually customize the primary Ionic variables, view your live changes immediately in several previews, and download a compiled css file with your edits. ## Contributing Currently the Ionic Theme Editor is hosted in a heroku app. All changes inbetween each release are made to the github repo. I use grunt to build the files. To get setup: ``` git clone https://github.com/pbernasconi/ionic-theme-editor.git cd ionic-theme-editor npm install bower install grunt build grunt serve ``` Make a new Pull Request for any changes you think are necessary! ## Authors #### Paolo Bernasconi - https://twitter.com/paolobernasconi - https://github.com/pbernasconi ## LICENSE Ionic Theme Editor is licensed under the MIT Open Source license. For more information, see the LICENSE file in this repository. ================================================ FILE: bower.json ================================================ { "name": "projects", "version": "0.0.1", "dependencies": { "angular": ">=1.2.*", "json3": "~3.3.1", "es5-shim": "~3.0.1", "jquery": "~1.11.0", "bootstrap": "~3.1.1", "angular-resource": ">=1.2.*", "angular-cookies": ">=1.2.*", "angular-sanitize": ">=1.2.*", "angular-bootstrap": "~0.11.0", "font-awesome": ">=4.1.0", "lodash": "~2.4.1", "angular-ui-router": "~0.2.10", "angular-spectrum-colorpicker": "~1.2.0", "ionicons": "~1.5.2", "ngDialog": "~0.3.0" }, "devDependencies": { "angular-mocks": ">=1.2.*", "angular-scenario": ">=1.2.*", "angular-spectrum-colorpicker": "~1.2.0" } } ================================================ FILE: client/.htaccess ================================================ # Apache Configuration File # (!) Using `.htaccess` files slows down Apache, therefore, if you have access # to the main server config file (usually called `httpd.conf`), you should add # this logic there: http://httpd.apache.org/docs/current/howto/htaccess.html. # ############################################################################## # # CROSS-ORIGIN RESOURCE SHARING (CORS) # # ############################################################################## # ------------------------------------------------------------------------------ # | Cross-domain AJAX requests | # ------------------------------------------------------------------------------ # Enable cross-origin AJAX requests. # http://code.google.com/p/html5security/wiki/CrossOriginRequestSecurity # http://enable-cors.org/ # # Header set Access-Control-Allow-Origin "*" # # ------------------------------------------------------------------------------ # | CORS-enabled images | # ------------------------------------------------------------------------------ # Send the CORS header for images when browsers request it. # https://developer.mozilla.org/en/CORS_Enabled_Image # http://blog.chromium.org/2011/07/using-cross-domain-images-in-webgl-and.html # http://hacks.mozilla.org/2011/11/using-cors-to-load-webgl-textures-from-cross-domain-images/ SetEnvIf Origin ":" IS_CORS Header set Access-Control-Allow-Origin "*" env=IS_CORS # ------------------------------------------------------------------------------ # | Web fonts access | # ------------------------------------------------------------------------------ # Allow access from all domains for web fonts Header set Access-Control-Allow-Origin "*" # ############################################################################## # # ERRORS # # ############################################################################## # ------------------------------------------------------------------------------ # | 404 error prevention for non-existing redirected folders | # ------------------------------------------------------------------------------ # Prevent Apache from returning a 404 error for a rewrite if a directory # with the same name does not exist. # http://httpd.apache.org/docs/current/content-negotiation.html#multiviews # http://www.webmasterworld.com/apache/3808792.htm Options -MultiViews # ------------------------------------------------------------------------------ # | Custom error messages / pages | # ------------------------------------------------------------------------------ # You can customize what Apache returns to the client in case of an error (see # http://httpd.apache.org/docs/current/mod/core.html#errordocument), e.g.: ErrorDocument 404 /404.html # ############################################################################## # # INTERNET EXPLORER # # ############################################################################## # ------------------------------------------------------------------------------ # | Better website experience | # ------------------------------------------------------------------------------ # Force IE to render pages in the highest available mode in the various # cases when it may not: http://hsivonen.iki.fi/doctype/ie-mode.pdf. Header set X-UA-Compatible "IE=edge" # `mod_headers` can't match based on the content-type, however, we only # want to send this header for HTML pages and not for the other resources Header unset X-UA-Compatible # ------------------------------------------------------------------------------ # | Cookie setting from iframes | # ------------------------------------------------------------------------------ # Allow cookies to be set from iframes in IE. # # Header set P3P "policyref=\"/w3c/p3p.xml\", CP=\"IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT\"" # # ------------------------------------------------------------------------------ # | Screen flicker | # ------------------------------------------------------------------------------ # Stop screen flicker in IE on CSS rollovers (this only works in # combination with the `ExpiresByType` directives for images from below). # BrowserMatch "MSIE" brokenvary=1 # BrowserMatch "Mozilla/4.[0-9]{2}" brokenvary=1 # BrowserMatch "Opera" !brokenvary # SetEnvIf brokenvary 1 force-no-vary # ############################################################################## # # MIME TYPES AND ENCODING # # ############################################################################## # ------------------------------------------------------------------------------ # | Proper MIME types for all files | # ------------------------------------------------------------------------------ # Audio AddType audio/mp4 m4a f4a f4b AddType audio/ogg oga ogg # JavaScript # Normalize to standard type (it's sniffed in IE anyways): # http://tools.ietf.org/html/rfc4329#section-7.2 AddType application/javascript js jsonp AddType application/json json # Video AddType video/mp4 mp4 m4v f4v f4p AddType video/ogg ogv AddType video/webm webm AddType video/x-flv flv # Web fonts AddType application/font-woff woff AddType application/vnd.ms-fontobject eot # Browsers usually ignore the font MIME types and sniff the content, # however, Chrome shows a warning if other MIME types are used for the # following fonts. AddType application/x-font-ttf ttc ttf AddType font/opentype otf # Make SVGZ fonts work on iPad: # https://twitter.com/FontSquirrel/status/14855840545 AddType image/svg+xml svg svgz AddEncoding gzip svgz # Other AddType application/octet-stream safariextz AddType application/x-chrome-extension crx AddType application/x-opera-extension oex AddType application/x-shockwave-flash swf AddType application/x-web-app-manifest+json webapp AddType application/x-xpinstall xpi AddType application/xml atom rdf rss xml AddType image/webp webp AddType image/x-icon ico AddType text/cache-manifest appcache manifest AddType text/vtt vtt AddType text/x-component htc AddType text/x-vcard vcf # ------------------------------------------------------------------------------ # | UTF-8 encoding | # ------------------------------------------------------------------------------ # Use UTF-8 encoding for anything served as `text/html` or `text/plain`. AddDefaultCharset utf-8 # Force UTF-8 for certain file formats. AddCharset utf-8 .atom .css .js .json .rss .vtt .webapp .xml # ############################################################################## # # URL REWRITES # # ############################################################################## # ------------------------------------------------------------------------------ # | Rewrite engine | # ------------------------------------------------------------------------------ # Turning on the rewrite engine and enabling the `FollowSymLinks` option is # necessary for the following directives to work. # If your web host doesn't allow the `FollowSymlinks` option, you may need to # comment it out and use `Options +SymLinksIfOwnerMatch` but, be aware of the # performance impact: http://httpd.apache.org/docs/current/misc/perf-tuning.html#symlinks # Also, some cloud hosting services require `RewriteBase` to be set: # http://www.rackspace.com/knowledge_center/frequently-asked-question/why-is-mod-rewrite-not-working-on-my-site Options +FollowSymlinks # Options +SymLinksIfOwnerMatch RewriteEngine On # RewriteBase / # ------------------------------------------------------------------------------ # | Suppressing / Forcing the "www." at the beginning of URLs | # ------------------------------------------------------------------------------ # The same content should never be available under two different URLs especially # not with and without "www." at the beginning. This can cause SEO problems # (duplicate content), therefore, you should choose one of the alternatives and # redirect the other one. # By default option 1 (no "www.") is activated: # http://no-www.org/faq.php?q=class_b # If you'd prefer to use option 2, just comment out all the lines from option 1 # and uncomment the ones from option 2. # IMPORTANT: NEVER USE BOTH RULES AT THE SAME TIME! # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Option 1: rewrite www.example.com → example.com RewriteCond %{HTTPS} !=on RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC] RewriteRule ^ http://%1%{REQUEST_URI} [R=301,L] # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Option 2: rewrite example.com → www.example.com # Be aware that the following might not be a good idea if you use "real" # subdomains for certain parts of your website. # # RewriteCond %{HTTPS} !=on # RewriteCond %{HTTP_HOST} !^www\..+$ [NC] # RewriteRule ^ http://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L] # # ############################################################################## # # SECURITY # # ############################################################################## # ------------------------------------------------------------------------------ # | Content Security Policy (CSP) | # ------------------------------------------------------------------------------ # You can mitigate the risk of cross-site scripting and other content-injection # attacks by setting a Content Security Policy which whitelists trusted sources # of content for your site. # The example header below allows ONLY scripts that are loaded from the current # site's origin (no inline scripts, no CDN, etc). This almost certainly won't # work as-is for your site! # To get all the details you'll need to craft a reasonable policy for your site, # read: http://html5rocks.com/en/tutorials/security/content-security-policy (or # see the specification: http://w3.org/TR/CSP). # # Header set Content-Security-Policy "script-src 'self'; object-src 'self'" # # Header unset Content-Security-Policy # # # ------------------------------------------------------------------------------ # | File access | # ------------------------------------------------------------------------------ # Block access to directories without a default document. # Usually you should leave this uncommented because you shouldn't allow anyone # to surf through every directory on your server (which may includes rather # private places like the CMS's directories). Options -Indexes # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Block access to hidden files and directories. # This includes directories used by version control systems such as Git and SVN. RewriteCond %{SCRIPT_FILENAME} -d [OR] RewriteCond %{SCRIPT_FILENAME} -f RewriteRule "(^|/)\." - [F] # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Block access to backup and source files. # These files may be left by some text editors and can pose a great security # danger when anyone has access to them. Order allow,deny Deny from all Satisfy All # ------------------------------------------------------------------------------ # | Secure Sockets Layer (SSL) | # ------------------------------------------------------------------------------ # Rewrite secure requests properly to prevent SSL certificate warnings, e.g.: # prevent `https://www.example.com` when your certificate only allows # `https://secure.example.com`. # # RewriteCond %{SERVER_PORT} !^443 # RewriteRule ^ https://example-domain-please-change-me.com%{REQUEST_URI} [R=301,L] # # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Force client-side SSL redirection. # If a user types "example.com" in his browser, the above rule will redirect him # to the secure version of the site. That still leaves a window of opportunity # (the initial HTTP connection) for an attacker to downgrade or redirect the # request. The following header ensures that browser will ONLY connect to your # server via HTTPS, regardless of what the users type in the address bar. # http://www.html5rocks.com/en/tutorials/security/transport-layer-security/ # # Header set Strict-Transport-Security max-age=16070400; # # ------------------------------------------------------------------------------ # | Server software information | # ------------------------------------------------------------------------------ # Avoid displaying the exact Apache version number, the description of the # generic OS-type and the information about Apache's compiled-in modules. # ADD THIS DIRECTIVE IN THE `httpd.conf` AS IT WILL NOT WORK IN THE `.htaccess`! # ServerTokens Prod # ############################################################################## # # WEB PERFORMANCE # # ############################################################################## # ------------------------------------------------------------------------------ # | Compression | # ------------------------------------------------------------------------------ # Force compression for mangled headers. # http://developer.yahoo.com/blogs/ydn/posts/2010/12/pushing-beyond-gzipping SetEnvIfNoCase ^(Accept-EncodXng|X-cept-Encoding|X{15}|~{15}|-{15})$ ^((gzip|deflate)\s*,?\s*)+|[X~-]{4,13}$ HAVE_Accept-Encoding RequestHeader append Accept-Encoding "gzip,deflate" env=HAVE_Accept-Encoding # Compress all output labeled with one of the following MIME-types # (for Apache versions below 2.3.7, you don't need to enable `mod_filter` # and can remove the `` and `` lines # as `AddOutputFilterByType` is still in the core directives). AddOutputFilterByType DEFLATE application/atom+xml \ application/javascript \ application/json \ application/rss+xml \ application/vnd.ms-fontobject \ application/x-font-ttf \ application/x-web-app-manifest+json \ application/xhtml+xml \ application/xml \ font/opentype \ image/svg+xml \ image/x-icon \ text/css \ text/html \ text/plain \ text/x-component \ text/xml # ------------------------------------------------------------------------------ # | Content transformations | # ------------------------------------------------------------------------------ # Prevent some of the mobile network providers from modifying the content of # your site: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.5. # # Header set Cache-Control "no-transform" # # ------------------------------------------------------------------------------ # | ETag removal | # ------------------------------------------------------------------------------ # Since we're sending far-future expires headers (see below), ETags can # be removed: http://developer.yahoo.com/performance/rules.html#etags. # `FileETag None` is not enough for every server. Header unset ETag FileETag None # ------------------------------------------------------------------------------ # | Expires headers (for better cache control) | # ------------------------------------------------------------------------------ # The following expires headers are set pretty far in the future. If you don't # control versioning with filename-based cache busting, consider lowering the # cache time for resources like CSS and JS to something like 1 week. ExpiresActive on ExpiresDefault "access plus 1 month" # CSS ExpiresByType text/css "access plus 1 year" # Data interchange ExpiresByType application/json "access plus 0 seconds" ExpiresByType application/xml "access plus 0 seconds" ExpiresByType text/xml "access plus 0 seconds" # Favicon (cannot be renamed!) ExpiresByType image/x-icon "access plus 1 week" # HTML components (HTCs) ExpiresByType text/x-component "access plus 1 month" # HTML ExpiresByType text/html "access plus 0 seconds" # JavaScript ExpiresByType application/javascript "access plus 1 year" # Manifest files ExpiresByType application/x-web-app-manifest+json "access plus 0 seconds" ExpiresByType text/cache-manifest "access plus 0 seconds" # Media ExpiresByType audio/ogg "access plus 1 month" ExpiresByType image/gif "access plus 1 month" ExpiresByType image/jpeg "access plus 1 month" ExpiresByType image/png "access plus 1 month" ExpiresByType video/mp4 "access plus 1 month" ExpiresByType video/ogg "access plus 1 month" ExpiresByType video/webm "access plus 1 month" # Web feeds ExpiresByType application/atom+xml "access plus 1 hour" ExpiresByType application/rss+xml "access plus 1 hour" # Web fonts ExpiresByType application/font-woff "access plus 1 month" ExpiresByType application/vnd.ms-fontobject "access plus 1 month" ExpiresByType application/x-font-ttf "access plus 1 month" ExpiresByType font/opentype "access plus 1 month" ExpiresByType image/svg+xml "access plus 1 month" # ------------------------------------------------------------------------------ # | Filename-based cache busting | # ------------------------------------------------------------------------------ # If you're not using a build process to manage your filename version revving, # you might want to consider enabling the following directives to route all # requests such as `/css/style.12345.css` to `/css/style.css`. # To understand why this is important and a better idea than `*.css?v231`, read: # http://stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring # # RewriteCond %{REQUEST_FILENAME} !-f # RewriteCond %{REQUEST_FILENAME} !-d # RewriteRule ^(.+)\.(\d+)\.(js|css|png|jpg|gif)$ $1.$3 [L] # # ------------------------------------------------------------------------------ # | File concatenation | # ------------------------------------------------------------------------------ # Allow concatenation from within specific CSS and JS files, e.g.: # Inside of `script.combined.js` you could have # # # and they would be included into this single file. # # # Options +Includes # AddOutputFilterByType INCLUDES application/javascript application/json # SetOutputFilter INCLUDES # # # Options +Includes # AddOutputFilterByType INCLUDES text/css # SetOutputFilter INCLUDES # # # ------------------------------------------------------------------------------ # | Persistent connections | # ------------------------------------------------------------------------------ # Allow multiple requests to be sent over the same TCP connection: # http://httpd.apache.org/docs/current/en/mod/core.html#keepalive. # Enable if you serve a lot of static content but, be aware of the # possible disadvantages! # # Header set Connection Keep-Alive # ================================================ FILE: client/.jshintrc ================================================ { "node": true, "browser": true, "esnext": true, "bitwise": true, "camelcase": true, "curly": true, "eqeqeq": true, "immed": true, "indent": 2, "latedef": true, "newcap": true, "noarg": true, "quotmark": "single", "regexp": true, "undef": true, "unused": true, "strict": true, "trailing": true, "smarttabs": true, "globals": { "jQuery": true, "angular": true, "console": true, "$": true, "_": true, "moment": true, "describe": true, "beforeEach": true, "module": true, "inject": true, "it": true, "expect": true, "browser": true, "element": true, "by": true } } ================================================ FILE: client/app/app.css ================================================ /************************************************** * Bootstrap Fonts */ @font-face { font-family: 'Glyphicons Halflings'; src: url('../bower_components/bootstrap/fonts/glyphicons-halflings-regular.eot'); src: url('../bower_components/bootstrap/fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../bower_components/bootstrap/fonts/glyphicons-halflings-regular.woff') format('woff'), url('../bower_components/bootstrap/fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../bower_components/bootstrap/fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg'); } /************************************************** *Font Awesome Fonts */ @font-face { font-family: 'FontAwesome'; src: url('../bower_components/font-awesome/fonts/fontawesome-webfont.eot?v=4.1.0'); src: url('../bower_components/font-awesome/fonts/fontawesome-webfont.eot?#iefix&v=4.1.0') format('embedded-opentype'), url('../bower_components/font-awesome/fonts/fontawesome-webfont.woff?v=4.1.0') format('woff'), url('../bower_components/font-awesome/fonts/fontawesome-webfont.ttf?v=4.1.0') format('truetype'), url('../bower_components/font-awesome/fonts/fontawesome-webfont.svg?v=4.1.0#fontawesomeregular') format('svg'); font-weight: 200; font-style: normal; } /************************************************** * App-wide Styles */ .browsehappy { margin: 0.2em 0; background: #ccc; color: #000; padding: 0.2em 0; } html, body { font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; height: 100%; overflow: hidden; color: #575859; } ul { list-style: none; } .row { margin: 0 0 30px; } /*************************************************** * SIDE PANEL */ .side-panel { position: absolute; left: 0; width: 325px; height: 100%; } .side-panel section::-webkit-scrollbar { display: none; } /** * HEADER */ .side-panel > header { display: inline-block; width: 100%; height: 55px; line-height: 55px; color: white; background-color: #6795F5; z-index: 10; } .side-panel > header .logo { float: left; padding-left: 10px; height: 45px; padding-top: 8px; vertical-align: middle; } .side-panel > header .logo-title { float: left; margin-left: 15px; font-weight: 200; font-size: 15px; letter-spacing: 2px; border-top: 2px solid transparent; text-transform: uppercase; } /** * BUTTON ROW */ .side-panel .sub-header { background: #ffFFFF; height: 50px; line-height: 50px; text-align: center; border-right: solid #ECF0F6 1px; margin-top: -5px; width: 100%; border-bottom: 1px solid #ECF0F6; z-index: 10; box-shadow: -2px 4px 8px rgba(250, 250, 250, 0.7); -webkit-box-shadow: -2px 4px 8px rgba(250, 250, 250, 0.7); -moz-box-shadow: -2px 4px 8px rgba(250, 250, 250, 0.7); } .sub-header .button-row { display: inline-block; margin: 0; } .sub-header .button-row a { color: #575859; display: inline-block; border: 1px solid #575859; text-decoration: none; height: 30px; line-height: 30px; text-transform: uppercase; letter-spacing: 1px; font-weight: 200; width: 130px; font-size: 12px; cursor: pointer; -webkit-transition: 200ms; -moz-transition: 200ms; -ms-transition: 200ms; -o-transition: 200ms; transition: 200ms; } .sub-header .button-row a:first-child { border-radius: 5px 0 0 5px; border-right: none; } .sub-header .button-row a:last-child { margin-left: -5px; border-radius: 0 5px 5px 0; } .sub-header .button-row a.selected { background-color: #575859; color: #ffFFFF; -webkit-transition: 200ms; -moz-transition: 200ms; -ms-transition: 200ms; -o-transition: 200ms; transition: 200ms; } /** * SECTION */ .side-panel section { position: absolute; height: 93%; width: 100%; overflow: auto; border-right: solid #ECF0F6 1px; } .side-panel .side-section-download { padding: 20px; } .side-panel .btn-download { width: 100%; background-color: #6795F5; color: #fFF; font-size: 15px; letter-spacing: 1px; font-weight: 200; text-transform: uppercase; border: 1px solid #6795F5; -webkit-transition: all 0.20s ease-in-out; -moz-transition: all 0.20s ease-in-out; -ms-transition: all 0.20s ease-in-out; -o-transition: all 0.20s ease-in-out; } .side-panel .btn-download:hover, .side-panel .btn-download:focus { outline: none; border: 1px solid #6795F5; color: #6795F5; background-color: #FFFFFF; -webkit-transition: all 0.20s ease-in-out; -moz-transition: all 0.20s ease-in-out; -ms-transition: all 0.20s ease-in-out; -o-transition: all 0.20s ease-in-out; } /* side-section - headers */ .side-section .side-section-header { display: inline-block; background-color: #F3F5F7; width: 100%; height: 40px; line-height: 40px; letter-spacing: 2px; font-size: 13px; padding: 0 10px; text-transform: uppercase; } .side-section .btn-revert { font-size: 1.1em; position: relative; float: right; margin-right: 8px; display: inline-block; background-color: transparent; padding-top: 5px; border: none; outline: none; } .side-section .btn-revert:hover, .side-section .btn-revert:active { color: #ff4f5a; } /* side-section - colors */ .side-section ul { list-style: none; padding-left: 20px; } .side-section li { padding: 10px 0; border-bottom: 1px solid #ECF0F6; } .side-section li:last-child { border-bottom: none; margin-bottom: 15px; } .side-section .section-color-preview { float: right; color: #93969F; margin-right: 10px; } .side-section-input { float: right; text-align: right; width: 70px; margin-right: 20px; border: 1px solid #ECF0F6; border-radius: 2px; padding-right: 5px; padding-top: 2px; padding-bottom: 2px; -webkit-transition: all 0.30s ease-in-out; -moz-transition: all 0.30s ease-in-out; -ms-transition: all 0.30s ease-in-out; -o-transition: all 0.30s ease-in-out; } .side-section-input:focus, .side-section-input:hover { border: 1px solid #6795F5; outline: none; } .side-section-select { float: right; text-align: right; width: 120px; margin-right: 20px; border: 1px solid #ECF0F6; border-radius: 2px; padding-right: 5px; padding-top: 3px; padding-bottom: 2px; -webkit-transition: all 0.30s ease-in-out; -moz-transition: all 0.30s ease-in-out; -ms-transition: all 0.30s ease-in-out; -o-transition: all 0.30s ease-in-out; } .side-section-select:focus, .side-section-select:hover { border: 1px solid #6795F5; outline: none; } /* side-section - footer */ .side-section-footer { position: absolute; background-color: #2B3442; padding-top: 4px; text-align: center; width: 100%; color: white; height: 50px; } .side-section-footer h4 { font-weight: lighter !important; font-size: 14px; letter-spacing: 1px; } /**************************************************** * COLOR PICKER */ .sp-container { background-color: #EFF1F5; border: 1px solid #eceef0; border-radius: 2px; } .sp-picker-container { border: none; } .sp-color { border: none; border-radius: 2px; } .sp-hue { border: none; border-radius: 2px; } .sp-alpha-inner { border: none; } .sp-slider { border-color: #575859; border-radius: 1px; opacity: 1; } .sp-alpha-handle { border-color: #575859; border-radius: 1px; opacity: 1; } .sp-replacer { float: right; margin-right: 20px; background-color: transparent; padding: 0; border: none; width: 23px; height: 23px; } .sp-replacer .sp-preview { margin: 0; border: 1px solid #ECF0F6; width: 23px; height: 23px; } .sp-dd { display: none; } input.sp-input { background-color: #ffFFFF; border: 1px solid #6795F5; border-radius: 2px; padding: 5px; -webkit-transition: all 0.30s ease-in-out; -moz-transition: all 0.30s ease-in-out; -ms-transition: all 0.30s ease-in-out; -o-transition: all 0.30s ease-in-out; } input.sp-input:focus, input.sp-input:hover { outline: none; border: 1px solid #6795F5; } .sp-cancel { background: #ff4843; text-shadow: none; color: #fFF !important; border-radius: 3px; padding: 4px; letter-spacing: 1px; font-size: 11px; font-weight: 200; text-transform: uppercase; border: 1px solid #ff4843; } .sp-cancel:hover { background: #FFF; text-decoration: none; color: #ff4843 !important; border: 1px solid #ff4843; } .sp-button-container > button { background: #6795F5; text-shadow: none; color: #fFF; letter-spacing: 1px; font-size: 11px; font-weight: 200; text-transform: uppercase; border: 1px solid #6795F5; } .sp-button-container > button:hover { border: 1px solid #6795F5; background: #FFF !important; color: #6795F5; text-shadow: none; } /**************************************************** * MAIN PANEL */ .main-panel { position: absolute; top: 0; left: 325px; bottom: 0; right: 0; height: 100%; } /* Main - tabs */ .main-panel-tabs { list-style: none; height: 55px; line-height: 55px; color: white; background-color: #6795F5; font-weight: lighter; letter-spacing: 1px; z-index: 10; } .main-panel-tabs > li { font-size: 18px; list-style: none; box-sizing: border-box; margin-right: 20px; display: inline-block; border-top: 2px solid transparent; cursor: pointer; } .main-panel-tabs > li:hover { border-top: 2px solid white; cursor: pointer; } .main-panel-tabs > li.active { border-top: 2px solid white; cursor: pointer; } .main-panel-tabs .tabs-left { float: right; } .main-panel-tabs .tabs-left > .btn-login { background-color: transparent; border: none; color: white; text-decoration: none; } .main-panel-tabs .tabs-left > .btn-login:hover, .main-panel-tabs .tabs-left > .btn-login:focus { border: none; outline: none; } .main-panel .main-panel-view { position: absolute; top: 55px; right: 0; bottom: 0; left: 0; overflow: auto; width: 100%; overflow-x: hidden; } .main-panel-view .preview-card { height: 150px; border-top: 3px solid #93969F; box-shadow: 0 1px 3px #e0e4ea; margin: 0 8px 34px 8px; list-style: none; display: inline-block; width: 300px; } .preview-card .card-header { background-color: #ECF0F6; padding: 5px; font-size: 15px; font-weight: bold; } .preview-card .card-content { padding: 5px; } /**************************************************** * DEVICE PREVIEW */ .device-header { text-align: center; } .device-bg { background-image: url("../assets/images/device.png"); background-size: 243px 528px; height: 528px; width: 243px; margin-left: auto; margin-right: auto; } .device-screen { position: relative; top: 69px; left: 8px; z-index: 0; width: 341px; height: 576px; border: 2px solid #22272d; background-color: white; -ms-zoom: 0.665; -moz-transform: scale(0.665); -moz-transform-origin: 0 0; -o-transform: scale(0.665); -o-transform-origin: 0 0; -webkit-transform: scale(0.665); -webkit-transform-origin: 0 0; } /**************************************************** * SPINNER */ .spinner-background { width: 100%; height: 100%; position: absolute; background: rgba(255, 255, 255, 0.33); background: -moz-radial-gradient(center, ellipse cover, rgba(255, 255, 255, 0.33) 0%, rgba(255, 255, 255, 0.32) 6%, rgba(75, 140, 244, 0.17) 100%); background: -webkit-gradient(radial, center center, 0px, center center, 100%, color-stop(0%, rgba(255, 255, 255, 0.33)), color-stop(6%, rgba(255, 255, 255, 0.32)), color-stop(100%, rgba(75, 140, 244, 0.17))); background: -webkit-radial-gradient(center, ellipse cover, rgba(255, 255, 255, 0.33) 0%, rgba(255, 255, 255, 0.32) 6%, rgba(75, 140, 244, 0.17) 100%); background: -o-radial-gradient(center, ellipse cover, rgba(255, 255, 255, 0.33) 0%, rgba(255, 255, 255, 0.32) 6%, rgba(75, 140, 244, 0.17) 100%); background: -ms-radial-gradient(center, ellipse cover, rgba(255, 255, 255, 0.33) 0%, rgba(255, 255, 255, 0.32) 6%, rgba(75, 140, 244, 0.17) 100%); background: radial-gradient(ellipse at center, rgba(255, 255, 255, 0.33) 0%, rgba(255, 255, 255, 0.32) 6%, rgba(75, 140, 244, 0.17) 100%); filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#4b8cf4', GradientType=1); } .spinner { width: 40px; height: 40px; position: relative; padding: 10px; margin-left: auto; margin-right: auto; margin-top: 300px; } .double-bounce1, .double-bounce2 { width: 100%; height: 100%; border-radius: 50%; background-color: #6795F5; opacity: 0.6; position: absolute; top: 0; left: 0; -webkit-animation: bounce 2.0s infinite ease-in-out; animation: bounce 2.0s infinite ease-in-out; } .double-bounce2 { -webkit-animation-delay: -1.0s; animation-delay: -1.0s; } @-webkit-keyframes bounce { 0%, 100% { -webkit-transform: scale(0.0) } 50% { -webkit-transform: scale(1.0) } } @keyframes bounce { 0%, 100% { transform: scale(0.0); -webkit-transform: scale(0.0); } 50% { transform: scale(1.0); -webkit-transform: scale(1.0); } } /**************************************************** * DOWNLOAD MODAL */ .ngdialog-content { background: #ffffff !important; border-radius: 1px !important; border: 3px solid #6795F5; color: #575859 !important; margin: 0 auto; max-width: 100%; padding: 1em; position: relative; width: 550px !important; } .imodal { width: 100%; } .imodal-title { text-align: center; padding-bottom: 20px; border-bottom: 1px solid #ECF0F6; margin-bottom: 20px; } .imodal-content { padding: 20px; width: 70%; margin-right: auto; margin-left: auto; margin-bottom: 30px; } .imodal-content .input-group { padding: 10px; } .imodal-content .input-group:first-child { border-bottom: 1px solid #ECF0F6; } .imodal-content label { margin-right: 15px; } .imodal-content input { border: 1px solid #ECF0F6; border-radius: 2px; padding: 2px 8px; -webkit-transition: all 0.30s ease-in-out; -moz-transition: all 0.30s ease-in-out; -ms-transition: all 0.30s ease-in-out; -o-transition: all 0.30s ease-in-out; } .imodal-content input:focus, .imodal-content input:hover { border: 1px solid #6795F5; outline: none; } .imodal-buttons { width: 100%; margin: 0 auto; display: inline-block; } .imodal .btn-modal { width: 49%; margin-right: auto; margin-left: auto; } .imodal .btn-modal-cancel { margin-left: 3px; background: white; border: 1px solid #ff4843; color: #ff4843; -webkit-transition: all 0.30s ease-in-out; -moz-transition: all 0.30s ease-in-out; -ms-transition: all 0.30s ease-in-out; -o-transition: all 0.30s ease-in-out; } .imodal .btn-modal-cancel:hover, .imodal .btn-modal-cancel:focus { outline: none; border: 1px solid #ff4843; color: white; background-color: #ff4843; -webkit-transition: all 0.30s ease-in-out; -moz-transition: all 0.30s ease-in-out; -ms-transition: all 0.30s ease-in-out; -o-transition: all 0.30s ease-in-out; } .imodal .btn-modal-download { background: #6795F5; color: #fFF; border: 1px solid #6795F5; -webkit-transition: all 0.30s ease-in-out; -moz-transition: all 0.30s ease-in-out; -ms-transition: all 0.30s ease-in-out; -o-transition: all 0.30s ease-in-out; } .imodal .btn-modal-download:hover, .imodal .btn-modal-download:focus { outline: none; border: 1px solid #6795F5; color: #6795F5; background-color: #FFFFFF; -webkit-transition: all 0.30s ease-in-out; -moz-transition: all 0.30s ease-in-out; -ms-transition: all 0.30s ease-in-out; -o-transition: all 0.30s ease-in-out; } .ngdialog.ngdialog-theme-default .ngdialog-close:before { background: #6795F5; border-radius: 0 !important; color: white; content: '\00D7'; right: 0; top: -1px; } .ngdialog-close:hover:before { color: #575859 !important; } .icon-lg { font-size: 1.75em; line-height: 1; } ================================================ FILE: client/app/app.js ================================================ 'use strict'; angular.module('projectsApp', [ 'ngCookies', 'ngResource', 'ngSanitize', 'ui.router', 'ui.bootstrap', 'angularSpectrumColorpicker', 'ngDialog' ]) .config(function ($stateProvider, $urlRouterProvider, $locationProvider) { $urlRouterProvider .otherwise('/'); $locationProvider.html5Mode(true); }); ================================================ FILE: client/app/compiler/compiler.service.js ================================================ 'use strict'; angular.module('projectsApp') .service('Compiler', function ($http) { return { get: function (data) { return $http.get('/api/compile/'); }, post: function (data, cssType) { return $http.post('/api/compile/' + cssType, data); } } }); ================================================ FILE: client/app/compiler/compiler.service.spec.js ================================================ 'use strict'; describe('Service: compiler', function () { // load the service's module beforeEach(module('projectsApp')); // instantiate service var compiler; beforeEach(inject(function (_compiler_) { compiler = _compiler_; })); it('should do something', function () { expect(!!compiler).toBe(true); }); }); ================================================ FILE: client/app/main/main.controller.js ================================================ "use strict"; angular.module("projectsApp") .controller("MainCtrl", function ($scope, $timeout, ngDialog) { // initial variables $scope.activeTab = 1; $scope.selectedButtonBar = 0; $scope.iframeLoaded = false; // Global variables $scope.globals = [ {name: "Background Color", variable: "$base-background-color", value: "#fff", type: "color"}, {name: "Text Color", variable: "$base-color", value: "#000", type: "color"}, {name: "Link Color", variable: "$link-color", value: "#4a87ee", type: "color"} ]; // Color variables $scope.colors = [ {name: "light", variable: "$light", value: "#fff", type: "color"}, {name: "stable", variable: "$stable", value: "#f8f8f8", type: "color"}, {name: "positive", variable: "$positive", value: "#4a87ee", type: "color"}, {name: "calm", variable: "$calm", value: "#43cee6", type: "color"}, {name: "balanced", variable: "$balanced", value: "#66cc33", type: "color"}, {name: "energized", variable: "$energized", value: "#f0b840", type: "color"}, {name: "assertive", variable: "$assertive", value: "#ef4e3a", type: "color"}, {name: "royal", variable: "$royal", value: "#8a6de9", type: "color"}, {name: "dark", variable: "$dark", value: "#444", type: "color"} ]; // Font variables $scope.fonts = [ {name: "Font Family", variable: "$font-family-base", value: "$font-family-sans-serif", type: "select"}, {name: "Base - font size", variable: "$font-size-base", value: "14px", type: "pixel"}, {name: "Large - font size", variable: "$font-size-large", value: "18px", type: "pixel"}, {name: "Small - font size", variable: "$font-size-small", value: "11px", type: "pixel"} ]; // Padding variables $scope.padding = [ {name: "Content Padding", variable: "$content-padding", value: "10px", type: "pixel"}, {name: "Base - Vertical", variable: "$padding-base-vertical", value: "6px", type: "pixel"}, {name: "Base - Horizontal", variable: "$padding-base-horizontal", value: "12px", type: "pixel"}, {name: "Small - Vertical", variable: "$padding-small-vertical", value: "5px", type: "pixel"}, {name: "Small - Horizontal", variable: "$padding-small-horizontal", value: "10px", type: "pixel"}, {name: "Large - Vertical", variable: "$padding-large-vertical", value: "10px", type: "pixel"}, {name: "Large - Horizontal", variable: "$padding-large-horizontal", value: "16px", type: "pixel"} ]; // collect all data together $scope.groupedVars = _.union($scope.globals, $scope.colors, $scope.fonts, $scope.padding); // make copies for revert case var globalsCopy = angular.copy($scope.globals); var colorsCopy = angular.copy($scope.colors); var fontsCopy = angular.copy($scope.fonts); var paddingCopy = angular.copy($scope.padding); // setting the button-bar radio like $scope.setButtonBar = function (index) { $scope.selectedButtonBar = index; }; // return index of selected button bar $scope.isButtonBar = function (index) { return index === $scope.selectedButtonBar; }; // revert to original data with switch - case $scope.revert = function (list) { switch (list) { case "globals" : var _gCopy = angular.copy(globalsCopy); _.each($scope.globals, function (item, index) { item.value = _gCopy[index].value; }); break; case "colors" : var _cCopy = angular.copy(colorsCopy); _.each($scope.colors, function (item, index) { item.value = _cCopy[index].value; }); break; case "fonts" : var _fCopy = angular.copy(fontsCopy); _.each($scope.fonts, function (item, index) { item.value = _fCopy[index].value; }); break; case "padding" : var _pCopy = angular.copy(paddingCopy); _.each($scope.padding, function (item, index) { item.value = _pCopy[index].value; }); break; default : break; } }; // set the active tab $scope.setActiveTab = function (index) { if (index == 1) { $scope.iframeLoaded = false; $scope.iframeCallback(); } return $scope.activeTab = index; }; // iframe loaded $scope.iframeCallback = function () { $timeout(function () { $scope.iframeLoaded = true; }, 1000); }; // open modal with download button $scope.prepDownload = function () { ngDialog.open({ template: 'downloadModal', data: {sassData: $scope.groupedVars}, controller: 'DownloadModal', scope: $scope }) }; }) // Download Controller for modal .controller("DownloadModal", function ($scope, ngDialog, Compiler) { $scope.filename = "ionic.app.css"; $scope.cssType = "compressed"; var data = $scope.groupedVars; $scope.modalDownload = function () { Compiler.post(data, $scope.cssType) .success(function (response) { if (response.success == true) { var id = response.id; console.log(id); var hiddenElement = document.createElement('a'); // create new A element and self click to download hiddenElement.href = '/api/compile/download/' + id + '/' + $scope.filename; hiddenElement.target = '_blank'; hiddenElement.download = 'ionic.app.css'; hiddenElement.click(); } }) .error(function (error) { console.log(error); alert("An error occurred : ", error); }) }; $scope.modalClose = function () { ngDialog.close(); }; }); ================================================ FILE: client/app/main/main.controller.spec.js ================================================ 'use strict'; describe('Controller: MainCtrl', function () { // load the controller's module beforeEach(module('projectsApp')); var MainCtrl, scope, $httpBackend; // Initialize the controller and a mock scope beforeEach(inject(function (_$httpBackend_, $controller, $rootScope) { $httpBackend = _$httpBackend_; $httpBackend.expectGET('/api/things') .respond(['HTML5 Boilerplate', 'AngularJS', 'Karma', 'Express']); scope = $rootScope.$new(); MainCtrl = $controller('MainCtrl', { $scope: scope }); })); it('should attach a list of things to the scope', function () { $httpBackend.flush(); expect(scope.awesomeThings.length).toBe(4); }); }); ================================================ FILE: client/app/main/main.css ================================================ ================================================ FILE: client/app/main/main.html ================================================
Ionic Tailor
Globals
  • {{item.name}}
Colors
  • {{item.name}}
Fonts
  • {{item.name}}
Padding
  • {{item.name}}
  • Header

    bar-positive

  • Header

    bar-positive

  • Header

    bar-positive

  • Header

    bar-positive

  • Header

    bar-positive

  • Header

    bar-positive

  • Header

    bar-positive

Header Bar

Button

List

Form

Tabs

Card

Components

Examples tab
================================================ FILE: client/app/main/main.js ================================================ 'use strict'; angular.module('projectsApp') .config(function ($stateProvider) { $stateProvider .state('main', { url: '/', templateUrl: 'app/main/main.html', controller: 'MainCtrl' }); }); ================================================ FILE: client/app/theme/theme.directive.js ================================================ 'use strict'; angular.module('projectsApp') .directive('theme', function () { return { restrict: 'EA', scope: { theme: '=', callBack: '&onLoad' }, link: function ($scope, $element, $attr) { var cw; $element.ready(function () { cw = $element[0].contentWindow; }); $element.on('load', function () { return $scope.callBack(); }); var updatePreview = function (colors) { if (!cw) { return; } cw.IonicThemer && cw.IonicThemer.update(colors); }; $scope.$watch('theme', function (nv, ov) { updatePreview(nv); }, true); } } }) .directive('autoFocus', function ($timeout) { return { restrict: 'AC', link: function (_scope, _element) { $timeout(function () { _element[0].focus(); }, 0); } }; }); ================================================ FILE: client/app/theme/theme.directive.spec.js ================================================ 'use strict'; describe('Directive: theme', function () { // load the directive's module beforeEach(module('projectsApp')); var element, scope; beforeEach(inject(function ($rootScope) { scope = $rootScope.$new(); })); it('should make hidden element visible', inject(function ($compile) { element = angular.element(''); element = $compile(element)(scope); expect(element.text()).toBe('this is the theme directive'); })); }); ================================================ FILE: client/components/preview/preview-buttons.html ================================================

BUTTONS

================================================ FILE: client/components/preview/preview-card.html ================================================

Title

Pretty Hate Machine

Nine Inch Nails

Start listening
================================================ FILE: client/components/preview/preview-components.html ================================================

Title

================================================ FILE: client/components/preview/preview-form.html ================================================

Title

Inline
Placeholder labels
Stacked Labels
Floating Labels
================================================ FILE: client/components/preview/preview-header.html ================================================

bar-light

bar-stable

bar-positive

bar-calm

bar-balanced

bar-energized

bar-assertive

bar-royal

bar-dark

================================================ FILE: client/components/preview/preview-list.html ================================================

Title

================================================ FILE: client/components/preview/preview-tabs.html ================================================

Title

================================================ FILE: client/index.html ================================================ Ionic Tailor
================================================ FILE: client/robots.txt ================================================ # robotstxt.org User-agent: * ================================================ FILE: e2e/main/main.po.js ================================================ /** * This file uses the Page Object pattern to define the main page for tests * https://docs.google.com/presentation/d/1B6manhG0zEXkC-H-tPo2vwU06JhL8w9-XCF9oehXzAQ */ 'use strict'; var MainPage = function() { this.heroEl = element(by.css('.hero-unit')); this.h1El = this.heroEl.element(by.css('h1')); this.imgEl = this.heroEl.element(by.css('img')); }; module.exports = new MainPage(); ================================================ FILE: e2e/main/main.spec.js ================================================ 'use strict'; describe('Main View', function() { var page; beforeEach(function() { browser.get('/'); page = require('./main.po'); }); it('should include jumbotron with correct data', function() { expect(page.h1El.getText()).toBe('\'Allo, \'Allo!'); expect(page.imgEl.getAttribute('src')).toMatch(/assets\/images\/yeoman.png$/); expect(page.imgEl.getAttribute('alt')).toBe('I\'m Yeoman'); }); }); ================================================ FILE: karma.conf.js ================================================ // Karma configuration // http://karma-runner.github.io/0.10/config/configuration-file.html module.exports = function(config) { config.set({ // base path, that will be used to resolve files and exclude basePath: '', // testing framework to use (jasmine/mocha/qunit/...) frameworks: ['jasmine'], // list of files / patterns to load in the browser files: [ 'client/bower_components/jquery/dist/jquery.js', 'client/bower_components/angular/angular.js', 'client/bower_components/angular-mocks/angular-mocks.js', 'client/bower_components/angular-resource/angular-resource.js', 'client/bower_components/angular-cookies/angular-cookies.js', 'client/bower_components/angular-sanitize/angular-sanitize.js', 'client/bower_components/angular-route/angular-route.js', 'client/bower_components/angular-bootstrap/ui-bootstrap-tpls.js', 'client/bower_components/lodash/dist/lodash.compat.js', 'client/bower_components/angular-ui-router/release/angular-ui-router.js', 'client/app/app.js', 'client/app/app.coffee', 'client/app/**/*.js', 'client/app/**/*.coffee', 'client/components/**/*.js', 'client/components/**/*.coffee', 'client/app/**/*.jade', 'client/components/**/*.jade', 'client/app/**/*.html', 'client/components/**/*.html' ], preprocessors: { '**/*.jade': 'ng-jade2js', '**/*.html': 'html2js', '**/*.coffee': 'coffee', }, ngHtml2JsPreprocessor: { stripPrefix: 'client/' }, ngJade2JsPreprocessor: { stripPrefix: 'client/' }, // list of files / patterns to exclude exclude: [], // web server port port: 8080, // level of logging // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG logLevel: config.LOG_INFO, // enable / disable watching file and executing tests whenever any file changes autoWatch: false, // Start these browsers, currently available: // - Chrome // - ChromeCanary // - Firefox // - Opera // - Safari (only Mac) // - PhantomJS // - IE (only Windows) browsers: ['PhantomJS'], // Continuous Integration mode // if true, it capture browsers, run tests and exit singleRun: false }); }; ================================================ FILE: package.json ================================================ { "name": "projects", "version": "0.0.0", "main": "server/app.js", "dependencies": { "body-parser": "~1.0.0", "composable-middleware": "^0.3.0", "compression": "~1.0.1", "connect-mongo": "^0.4.1", "cookie-parser": "~1.0.1", "ejs": "~0.8.4", "errorhandler": "~1.0.0", "express": "~4.8.0", "express-session": "~1.0.2", "lodash": "~2.4.1", "method-override": "~1.0.0", "mkdirp": "^0.5.0", "mongoose": "~3.8.8", "morgan": "~1.0.0", "node-sass": "^0.9.3", "request": "^2.42.0", "semver": "^3.0.1", "shortid": "^2.0.1", "static-favicon": "~1.0.1" }, "devDependencies": { "grunt": "~0.4.4", "grunt-autoprefixer": "~0.7.2", "grunt-bower-install": "~1.4.0", "grunt-concurrent": "~0.5.0", "grunt-contrib-clean": "~0.5.0", "grunt-contrib-concat": "~0.4.0", "grunt-contrib-copy": "~0.5.0", "grunt-contrib-cssmin": "~0.9.0", "grunt-contrib-htmlmin": "~0.2.0", "grunt-contrib-imagemin": "~0.7.1", "grunt-contrib-jshint": "~0.10.0", "grunt-contrib-uglify": "~0.4.0", "grunt-contrib-watch": "~0.6.1", "grunt-google-cdn": "~0.4.0", "grunt-newer": "~0.7.0", "grunt-ng-annotate": "^0.2.3", "grunt-rev": "~0.1.0", "grunt-svgmin": "~0.4.0", "grunt-usemin": "~2.1.1", "grunt-env": "~0.4.1", "grunt-node-inspector": "~0.1.5", "grunt-nodemon": "~0.2.0", "grunt-angular-templates": "^0.5.4", "grunt-dom-munger": "^3.4.0", "grunt-protractor-runner": "^1.1.0", "grunt-asset-injector": "^0.1.0", "grunt-karma": "~0.8.2", "grunt-mocha-test": "~0.10.2", "jit-grunt": "^0.5.0", "time-grunt": "~0.3.1", "grunt-express-server": "~0.4.17", "grunt-open": "~0.2.3", "open": "~0.0.4", "jshint-stylish": "~0.1.5", "connect-livereload": "~0.4.0", "karma-ng-scenario": "~0.1.0", "karma-firefox-launcher": "~0.1.3", "karma-script-launcher": "~0.1.0", "karma-html2js-preprocessor": "~0.1.0", "karma-ng-jade2js-preprocessor": "^0.1.2", "karma-jasmine": "~0.1.5", "karma-chrome-launcher": "~0.1.3", "requirejs": "~2.1.11", "karma-requirejs": "~0.2.1", "karma-coffee-preprocessor": "~0.2.1", "karma-jade-preprocessor": "0.0.11", "karma-phantomjs-launcher": "~0.1.4", "karma": "~0.12.9", "karma-ng-html2js-preprocessor": "~0.1.0", "supertest": "~0.11.0", "should": "~3.3.1" }, "engines": { "node": ">=0.10.0" }, "scripts": { "start": "node server/app.js", "test": "grunt test", "update-webdriver": "node node_modules/grunt-protractor-runner/node_modules/protractor/bin/webdriver-manager update" }, "private": true } ================================================ FILE: protractor.conf.js ================================================ // Protractor configuration // https://github.com/angular/protractor/blob/master/referenceConf.js 'use strict'; exports.config = { // The timeout for each script run on the browser. This should be longer // than the maximum time your application needs to stabilize between tasks. allScriptsTimeout: 110000, // A base URL for your application under test. Calls to protractor.get() // with relative paths will be prepended with this. baseUrl: 'http://localhost:' + (process.env.PORT || '9000'), // If true, only chromedriver will be started, not a standalone selenium. // Tests for browsers other than chrome will not run. chromeOnly: true, // list of files / patterns to load in the browser specs: [ 'e2e/**/*.spec.js' ], // Patterns to exclude. exclude: [], // ----- Capabilities to be passed to the webdriver instance ---- // // For a full list of available capabilities, see // https://code.google.com/p/selenium/wiki/DesiredCapabilities // and // https://code.google.com/p/selenium/source/browse/javascript/webdriver/capabilities.js capabilities: { 'browserName': 'chrome' }, // ----- The test framework ----- // // Jasmine and Cucumber are fully supported as a test and assertion framework. // Mocha has limited beta support. You will need to include your own // assertion framework if working with mocha. framework: 'jasmine', // ----- Options to be passed to minijasminenode ----- // // See the full list at https://github.com/juliemr/minijasminenode jasmineNodeOpts: { defaultTimeoutInterval: 30000 } }; ================================================ FILE: server/.jshintrc ================================================ { "node": true, "esnext": true, "bitwise": true, "eqeqeq": true, "immed": true, "latedef": true, "newcap": true, "noarg": true, "regexp": true, "undef": true, "smarttabs": true, "asi": true, "debug": true } ================================================ FILE: server/api/compile/compile.controller.js ================================================ 'use strict'; var _ = require('lodash'); var Compile = require('./compile.model'); var http = require('http'); var https = require('https'); var fs = require('fs'); var request = require('request'); var mkdirp = require('mkdirp'); var path = require('path'); var sass = require('node-sass'); var shortId = require('shortid'); // GET : download file, remove after success exports.download = function (req, res) { var id = req.params.id; var filename = req.params.filename || "ionic.app.css"; console.log(req.params.filename); var file = "./server/ionic/tmp/ionic-" + id + ".app.css"; res.download(path.resolve(file), filename, function (err) { // send file for download if (err) { console.log(err); throw err; } else { fs.unlink(path.resolve(file), function (err) { // delete file when done if (err) { console.log(err); throw err; } res.status(200); }); } }); }; // POST : Creates a new compile in the DB. exports.compile = function (req, res) { var postData = req.body; var cssType = req.params.cssType; var uniqueID = shortId.generate(); // generate a unique ID for tmp file var stats = {}; var sassString = ""; mkdirp('./server/ionic/tmp', function (err) { // create temporary folder if (err) { console.log(err); throw err; } }); console.log(cssType); if (cssType != "nested" && cssType != "compressed") { res.status(400).json({success: false, id: null, error: "Wrong CSS type"}).end(); } sassString += "$ionicons-font-path: '../../../ionic/scss/fonts' !default;"; sassString += "$font-family-sans-serif: 'Helvetica Neue', Helvetica, Arial, 'Lucida Grande', sans-serif !default;"; sassString += "$font-family-light-sans-serif:'Helvetica Neue-Light', 'Helvetica Neue Light', 'Helvetica Neue', Helvetica, Arial, 'Lucida Grande', sans-serif !default;" sassString += "$font-family-serif: Georgia, 'Times New Roman', Times, serif !default;"; sassString += "$font-family-monospace: Monaco, Menlo, Consolas, 'Courier New', monospace !default;"; _.each(postData, function (each) { // create variables SASS compiler string sassString += each.variable + ": " + each.value + " !default;\n"; }); sassString += "@import './server/ionic/scss-prod/ionic';"; // import ionic into SASS compiler string sass.renderFile({ data: sassString, success: function (css) { res.status(200).json({success: true, id: uniqueID}); }, error: function (error) { console.log(error); res.status(400).json({success: false, id: null, error: error}); }, outFile: "./server/ionic/tmp/ionic-" + uniqueID + ".app.css", outputStyle: cssType, stats: stats }); }; // GET : compile for live preview exports.live = function (req, res) { var reqData = req.query; var sassString = ""; res.set('Content-Type', 'text/css'); sassString += "$font-family-sans-serif: 'Helvetica Neue', Helvetica, Arial, 'Lucida Grande', sans-serif !default;"; sassString += "$font-family-light-sans-serif:'Helvetica Neue-Light', 'Helvetica Neue Light', 'Helvetica Neue', Helvetica, Arial, 'Lucida Grande', sans-serif !default;" sassString += "$font-family-serif: Georgia, 'Times New Roman', Times, serif !default;"; sassString += "$font-family-monospace: Monaco, Menlo, Consolas, 'Courier New', monospace !default;"; _.each(reqData, function (value, key) { sassString += key + ": " + value + " !default;\n"; }); sassString += "@import './server/ionic/scss-live/ionic';"; //sassString += "@function best-text-color($color) { @if (lightness( $color ) > 70) {@return #000000;} @else { @return #FFFFFF;}}"; //sassString += ".bar {&.bar-brand { @include bar-style($brand, lighten($brand, 50%), best-text-color($brand));} }"; var stats = {}; sass.render({ data: sassString, success: function (css) { res.send(css); }, error: function (error) { console.log(error); res.status(400).json({success: false, id: null}); }, includePaths: ['ionic/scss/ionic'], outputStyle: 'compressed', stats: stats }); }; // ??? : Update ionic sass files depending on latest version exports.update = function (req, res) { mkdirp('./server/ionic/scss_test', function (err) { // create new scss test folder if (!err == null) console.log(err); }); }; function getNightly(postData) { var outputString = ""; var ionicVersion = ""; var githubStr = "https://github.com/driftyco/ionic/blob/master/"; var rawgitStr = "https://cdn.rawgit.com/driftyco/ionic/master/"; request('https://cdn.rawgit.com/driftyco/ionic/master/package.json', function (error, response, body) { if (!error && response.statusCode == 200) { ionicVersion = JSON.parse(body).version; console.log(ionicVersion); var gitOptions = { url: 'https://api.github.com/repos/driftyco/ionic/contents/scss?', //ref=v' + ionicVersion, headers: {'User-Agent': 'request'} }; request(gitOptions, function (error, response, body) { if (!error && response.statusCode == 200) { var scss = JSON.parse(body); _.each(scss, function (each) { if (each.name != "ionicons") { var fileIn = each.html_url.replace(githubStr, rawgitStr); var fileOut = path.resolve("./server/ionic/scss/" + each.name); var options = { url: fileIn, headers: {'User-Agent': 'request'} }; request(options, function (error, res, bod) { fs.writeFile(path.resolve(fileOut), (bod), function (error) { if (error) console.log("error : " + error); else { _.each(postData, function (each) { outputString += each.variable + ": " + each.value + " !default;\n"; }); outputString += "@import './server/ionic/scss/ionic';"; var dateID = new Date().getTime(); CompileSass(outputString, dateID); } }); }); } }); } }); } }); } function CompileSass(outputString, dateID) { var stats = {}; sass.renderFile({ data: outputString, success: function (css) { //res.status(200).json({success: true, id: dateID}); }, error: function (error) { console.log(error); //res.status(400).json({success: false, id: null}); }, includePaths: ['ionic/scss/ionic'], outFile: "./server/ionic/tmp/ionic.app.css", // + dateID + ".css", outputStyle: 'nested', stats: stats }); } function handleError(res, err) { return res.send(500, err); } ================================================ FILE: server/api/compile/compile.model.js ================================================ 'use strict'; var mongoose = require('mongoose'), Schema = mongoose.Schema; var CompileSchema = new Schema({ name: String, info: String, active: Boolean }); module.exports = mongoose.model('Compile', CompileSchema); ================================================ FILE: server/api/compile/compile.spec.js ================================================ 'use strict'; var should = require('should'); var app = require('../../app'); var request = require('supertest'); describe('GET /api/compile', function() { it('should respond with JSON array', function(done) { request(app) .get('/api/compile') .expect(200) .expect('Content-Type', /json/) .end(function(err, res) { if (err) return done(err); res.body.should.be.instanceof(Array); done(); }); }); }); ================================================ FILE: server/api/compile/index.js ================================================ 'use strict'; var express = require('express'); var controller = require('./compile.controller'); var router = express.Router(); router.get('/download/:id/:filename', controller.download); // download ionic.css router.get('/live/ionic.css:data', controller.live); // post a live router.post('/:cssType', controller.compile); // post a new compile script router.get('/live/:body', controller.live); // post a live router.put('/:id', controller.update); module.exports = router; ================================================ FILE: server/api/themes/index.js ================================================ 'use strict'; var express = require('express'); var controller = require('./themes.controller'); var router = express.Router(); router.get('/', controller.index); router.get('/:id', controller.show); router.post('/', controller.create); router.put('/:id', controller.update); router.patch('/:id', controller.update); router.delete('/:id', controller.destroy); module.exports = router; ================================================ FILE: server/api/themes/themes.controller.js ================================================ 'use strict'; var _ = require('lodash'); var Themes = require('./themes.model'); // Get list of themess exports.index = function(req, res) { Themes.find(function (err, themess) { if(err) { return handleError(res, err); } return res.json(200, themess); }); }; // Get a single themes exports.show = function(req, res) { Themes.findById(req.params.id, function (err, themes) { if(err) { return handleError(res, err); } if(!themes) { return res.send(404); } return res.json(themes); }); }; // Creates a new themes in the DB. exports.create = function(req, res) { Themes.create(req.body, function(err, themes) { if(err) { return handleError(res, err); } return res.json(201, themes); }); }; // Updates an existing themes in the DB. exports.update = function(req, res) { if(req.body._id) { delete req.body._id; } Themes.findById(req.params.id, function (err, themes) { if (err) { return handleError(res, err); } if(!themes) { return res.send(404); } var updated = _.merge(themes, req.body); updated.save(function (err) { if (err) { return handleError(res, err); } return res.json(200, themes); }); }); }; // Deletes a themes from the DB. exports.destroy = function(req, res) { Themes.findById(req.params.id, function (err, themes) { if(err) { return handleError(res, err); } if(!themes) { return res.send(404); } themes.remove(function(err) { if(err) { return handleError(res, err); } return res.send(204); }); }); }; function handleError(res, err) { return res.send(500, err); } ================================================ FILE: server/api/themes/themes.model.js ================================================ 'use strict'; var mongoose = require('mongoose'), Schema = mongoose.Schema; var ThemesSchema = new Schema({ name: String, info: String, active: Boolean }); module.exports = mongoose.model('Themes', ThemesSchema); ================================================ FILE: server/api/themes/themes.spec.js ================================================ 'use strict'; var should = require('should'); var app = require('../../app'); var request = require('supertest'); describe('GET /api/themes', function() { it('should respond with JSON array', function(done) { request(app) .get('/api/themes') .expect(200) .expect('Content-Type', /json/) .end(function(err, res) { if (err) return done(err); res.body.should.be.instanceof(Array); done(); }); }); }); ================================================ FILE: server/app.js ================================================ /** * Main application file */ 'use strict'; // Set default node environment to development process.env.NODE_ENV = process.env.NODE_ENV || 'development'; var express = require('express'); var mongoose = require('mongoose'); var config = require('./config/environment'); // Connect to database mongoose.connect(config.mongo.uri, config.mongo.options); // Populate DB with sample dat // Setup server var app = express(); var server = require('http').createServer(app); require('./config/express')(app); require('./routes')(app); // Start server server.listen(config.port, config.ip, function () { console.log('Express server listening on %d, in %s mode', config.port, app.get('env')); }); // Expose app exports = module.exports = app; ================================================ FILE: server/components/errors/index.js ================================================ /** * Error responses */ 'use strict'; module.exports[404] = function pageNotFound(req, res) { var viewFilePath = '404'; var statusCode = 404; var result = { status: statusCode }; res.status(result.status); res.render(viewFilePath, function (err) { if (err) { return res.json(result, result.status); } res.render(viewFilePath); }); }; ================================================ FILE: server/config/environment/development.js ================================================ 'use strict'; // Development specific configuration // ================================== module.exports = { // MongoDB connection options mongo: { uri: 'mongodb://localhost/projects-dev' }, seedDB: true }; ================================================ FILE: server/config/environment/index.js ================================================ 'use strict'; var path = require('path'); var _ = require('lodash'); function requiredProcessEnv(name) { if(!process.env[name]) { throw new Error('You must set the ' + name + ' environment variable'); } return process.env[name]; } // All configurations will extend these options // ============================================ var all = { env: process.env.NODE_ENV, // Root path of server root: path.normalize(__dirname + '/../../..'), // Server port port: process.env.PORT || 9000, // Should we populate the DB with sample data? seedDB: false, // Secret for session, you will want to change this and make it an environment variable secrets: { session: 'projects-secret' }, // List of user roles userRoles: ['guest', 'user', 'admin'], // MongoDB connection options mongo: { options: { db: { safe: true } } }, }; // Export the config object based on the NODE_ENV // ============================================== module.exports = _.merge( all, require('./' + process.env.NODE_ENV + '.js') || {}); ================================================ FILE: server/config/environment/production.js ================================================ 'use strict'; // Production specific configuration // ================================= module.exports = { // Server IP ip: process.env.OPENSHIFT_NODEJS_IP || process.env.IP || undefined, // Server port port: process.env.OPENSHIFT_NODEJS_PORT || process.env.PORT || 8080, // MongoDB connection options mongo: { uri: process.env.MONGOLAB_URI || process.env.MONGOHQ_URL || process.env.OPENSHIFT_MONGODB_DB_URL+process.env.OPENSHIFT_APP_NAME || 'mongodb://localhost/projects' } }; ================================================ FILE: server/config/environment/test.js ================================================ 'use strict'; // Test specific configuration // =========================== module.exports = { // MongoDB connection options mongo: { uri: 'mongodb://localhost/projects-test' } }; ================================================ FILE: server/config/express.js ================================================ /** * Express configuration */ 'use strict'; var express = require('express'); var favicon = require('static-favicon'); var morgan = require('morgan'); var compression = require('compression'); var bodyParser = require('body-parser'); var methodOverride = require('method-override'); var cookieParser = require('cookie-parser'); var errorHandler = require('errorhandler'); var path = require('path'); var config = require('./environment'); module.exports = function(app) { var env = app.get('env'); app.set('views', config.root + '/server/views'); app.engine('html', require('ejs').renderFile); app.set('view engine', 'html'); app.use(compression()); app.use(bodyParser.urlencoded({ extended: false })); app.use(bodyParser.json()); app.use(methodOverride()); app.use(cookieParser()); if ('production' === env) { app.use(favicon(path.join(config.root, 'public', 'favicon.ico'))); app.use(express.static(path.join(config.root, 'public'))); app.set('appPath', config.root + '/public'); app.use(morgan('dev')); } if ('development' === env || 'test' === env) { app.use(require('connect-livereload')()); app.use(express.static(path.join(config.root, '.tmp'))); app.use(express.static(path.join(config.root, 'client'))); app.set('appPath', 'client'); app.use(morgan('dev')); app.use(errorHandler()); // Error handler - has to be last } }; ================================================ FILE: server/ionic/scss-live/_action-sheet.scss ================================================ /** * Action Sheets * -------------------------------------------------- */ .action-sheet-backdrop { @include transition(background-color 300ms ease-in-out); position: fixed; top: 0; left: 0; z-index: $z-index-action-sheet; width: 100%; height: 100%; background-color: rgba(0,0,0,0); &.active { background-color: rgba(0,0,0,0.4); } } .action-sheet-wrapper { @include translate3d(0, 100%, 0); @include transition(all ease-in-out 300ms); position: absolute; bottom: 0; width: 100%; } .action-sheet-up { @include translate3d(0, 0, 0); } .action-sheet { margin-left: $sheet-margin; margin-right: $sheet-margin; width: auto; z-index: $z-index-action-sheet; overflow: hidden; .button { display: block; padding: 1px; width: 100%; border-radius: 0; border-color: $sheet-options-border-color; background-color: transparent; color: $sheet-options-text-color; font-size: 21px; &:hover { color: $sheet-options-text-color; } &.destructive { color: #ff3b30; &:hover { color: #ff3b30; } } } .button.active, .button.activated { box-shadow: none; border-color: $sheet-options-border-color; color: $sheet-options-text-color; background: $sheet-options-bg-active-color; } } .action-sheet-has-icons .icon { position: absolute; left: 16px; } .action-sheet-title { padding: $sheet-margin * 2; color: #8f8f8f; text-align: center; font-size: 13px; } .action-sheet-group { margin-bottom: $sheet-margin; border-radius: $sheet-border-radius; background-color: #fff; overflow: hidden; .button { border-width: 1px 0px 0px 0px; } .button:first-child:last-child { border-width: 0; } } .action-sheet-options { background: $sheet-options-bg-color; } .action-sheet-cancel { .button { font-weight: 500; } } .action-sheet-open { pointer-events: none; &.modal-open .modal { pointer-events: none; } .action-sheet-backdrop { pointer-events: auto; } } .platform-android { .action-sheet-backdrop.active { background-color: rgba(0,0,0,0.2); } .action-sheet { margin: 0; .action-sheet-title, .button { text-align: left; border-color: transparent; font-size: 16px; color: inherit; } .action-sheet-title { font-size: 14px; padding: 16px; color: #666; } .button.active, .button.activated { background: #e8e8e8; } } .action-sheet-group { margin: 0; border-radius: 0; background-color: #fafafa; } .action-sheet-cancel { display: none; } .action-sheet-has-icons { .button { padding-left: 56px; } } } ================================================ FILE: server/ionic/scss-live/_animations.scss ================================================ // Slide up from the bottom, used for modals // ------------------------------- .slide-in-up { @include translate3d(0, 100%, 0); } .slide-in-up.ng-enter, .slide-in-up > .ng-enter { @include transition(all cubic-bezier(.1, .7, .1, 1) 400ms); } .slide-in-up.ng-enter-active, .slide-in-up > .ng-enter-active { @include translate3d(0, 0, 0); } .slide-in-up.ng-leave, .slide-in-up > .ng-leave { @include transition(all ease-in-out 250ms); } // Scale Out // Scale from hero (1 in this case) to zero // ------------------------------- @-webkit-keyframes scaleOut { from { -webkit-transform: scale(1); opacity: 1; } to { -webkit-transform: scale(0.8); opacity: 0; } } @keyframes scaleOut { from { transform: scale(1); opacity: 1; } to { transform: scale(0.8); opacity: 0; } } // Super Scale In // Scale from super (1.x) to duper (1 in this case) // ------------------------------- @-webkit-keyframes superScaleIn { from { -webkit-transform: scale(1.2); opacity: 0; } to { -webkit-transform: scale(1); opacity: 1 } } @keyframes superScaleIn { from { transform: scale(1.2); opacity: 0; } to { transform: scale(1); opacity: 1; } } ================================================ FILE: server/ionic/scss-live/_backdrop.scss ================================================ .backdrop { position: fixed; top: 0; left: 0; z-index: $z-index-backdrop; width: 100%; height: 100%; background-color: $loading-backdrop-bg-color; visibility: hidden; opacity: 0; &.visible { visibility: visible; } &.active { opacity: 1; } @include transition($loading-backdrop-fadein-duration opacity linear); } ================================================ FILE: server/ionic/scss-live/_badge.scss ================================================ /** * Badges * -------------------------------------------------- */ .badge { @include badge-style($badge-default-bg, $badge-default-text); z-index: $z-index-badge; display: inline-block; padding: 3px 8px; min-width: 10px; border-radius: $badge-border-radius; vertical-align: baseline; text-align: center; white-space: nowrap; font-weight: $badge-font-weight; font-size: $badge-font-size; line-height: $badge-line-height; &:empty { display: none; } } //Be sure to override specificity of rule that 'badge color matches tab color by default' .tabs .tab-item .badge, .badge { &.badge-light { @include badge-style($badge-light-bg, $badge-light-text); } &.badge-stable { @include badge-style($badge-stable-bg, $badge-stable-text); } &.badge-positive { @include badge-style($badge-positive-bg, $badge-positive-text); } &.badge-calm { @include badge-style($badge-calm-bg, $badge-calm-text); } &.badge-assertive { @include badge-style($badge-assertive-bg, $badge-assertive-text); } &.badge-balanced { @include badge-style($badge-balanced-bg, $badge-balanced-text); } &.badge-energized { @include badge-style($badge-energized-bg, $badge-energized-text); } &.badge-royal { @include badge-style($badge-royal-bg, $badge-royal-text); } &.badge-dark { @include badge-style($badge-dark-bg, $badge-dark-text); } } // Quick fix for labels/badges in buttons .button .badge { position: relative; top: -1px; } ================================================ FILE: server/ionic/scss-live/_bar.scss ================================================ /** * Bar (Headers and Footers) * -------------------------------------------------- */ .bar { @include display-flex(); @include translate3d(0,0,0); @include user-select(none); position: absolute; right: 0; left: 0; z-index: $z-index-bar; box-sizing: border-box; padding: $bar-padding-portrait; width: 100%; height: $bar-height; border-width: 0; border-style: solid; border-top: 1px solid transparent; border-bottom: 1px solid $bar-default-border; background-color: $bar-default-bg; /* border-width: 1px will actually create 2 device pixels on retina */ /* this nifty trick sets an actual 1px border on hi-res displays */ background-size: 0; @media (min--moz-device-pixel-ratio: 1.5), (-webkit-min-device-pixel-ratio: 1.5), (min-device-pixel-ratio: 1.5), (min-resolution: 144dpi), (min-resolution: 1.5dppx) { border: none; background-image: linear-gradient(0deg, $bar-default-border, $bar-default-border 50%, transparent 50%); background-position: bottom; background-size: 100% 1px; background-repeat: no-repeat; } &.bar-clear { border: none; background: none; color: #fff; .button { color: #fff; } .title { color: #fff; } } &.item-input-inset { .item-input-wrapper { margin-top: -1px; input { padding-left: 8px; width: 94%; height: 28px; background: transparent; } } } &.bar-light { @include bar-style($bar-light-bg, $bar-light-border, $bar-light-text); &.bar-footer{ background-image: linear-gradient(180deg, $bar-light-border, $bar-light-border 50%, transparent 50%); } } &.bar-stable { @include bar-style($bar-stable-bg, $bar-stable-border, $bar-stable-text); &.bar-footer{ background-image: linear-gradient(180deg, $bar-stable-border, $bar-stable-border 50%, transparent 50%); } } &.bar-positive { @include bar-style($bar-positive-bg, $bar-positive-border, $bar-positive-text); &.bar-footer{ background-image: linear-gradient(180deg, $bar-positive-border, $bar-positive-border 50%, transparent 50%); } } &.bar-calm { @include bar-style($bar-calm-bg, $bar-calm-border, $bar-calm-text); &.bar-footer{ background-image: linear-gradient(180deg, $bar-calm-border, $bar-calm-border 50%, transparent 50%); } } &.bar-assertive { @include bar-style($bar-assertive-bg, $bar-assertive-border, $bar-assertive-text); &.bar-footer{ background-image: linear-gradient(180deg, $bar-assertive-border, $bar-assertive-border 50%, transparent 50%); } } &.bar-balanced { @include bar-style($bar-balanced-bg, $bar-balanced-border, $bar-balanced-text); &.bar-footer{ background-image: linear-gradient(180deg, $bar-balanced-border, $bar-positive-border 50%, transparent 50%); } } &.bar-energized { @include bar-style($bar-energized-bg, $bar-energized-border, $bar-energized-text); &.bar-footer{ background-image: linear-gradient(180deg, $bar-energized-border, $bar-energized-border 50%, transparent 50%); } } &.bar-royal { @include bar-style($bar-royal-bg, $bar-royal-border, $bar-royal-text); &.bar-footer{ background-image: linear-gradient(180deg, $bar-royal-border, $bar-royal-border 50%, transparent 50%); } } &.bar-dark { @include bar-style($bar-dark-bg, $bar-dark-border, $bar-dark-text); &.bar-footer{ background-image: linear-gradient(180deg, $bar-dark-border, $bar-dark-border 50%, transparent 50%); } } // Title inside of a bar is centered .title { position: absolute; top: 0; right: 0; left: 0; z-index: $z-index-bar-title; overflow: hidden; margin: 0 10px; min-width: 30px; height: $bar-height - 1; text-align: center; // Go into ellipsis if too small text-overflow: ellipsis; white-space: nowrap; font-size: $bar-title-font-size; font-weight: $headings-font-weight; line-height: $bar-height; &.title-left { text-align: left; } &.title-right { text-align: right; } } .title a { color: inherit; } .button { z-index: $z-index-bar-button; padding: 0 $button-bar-button-padding; min-width: initial; min-height: $button-bar-button-height - 1; font-weight: 400; font-size: $button-bar-button-font-size; line-height: $button-bar-button-height; &.button-icon:before, .icon:before, &.icon:before, &.icon-left:before, &.icon-right:before { padding-right: 2px; padding-left: 2px; font-size: $button-bar-button-icon-size; line-height: $button-bar-button-height; } &.button-icon { font-size: $bar-title-font-size; .icon:before, &:before, &.icon-left:before, &.icon-right:before { vertical-align: top; font-size: $button-large-icon-size; line-height: $button-bar-button-height; } } &.button-clear { padding-right: 2px; padding-left: 2px; font-weight: 300; font-size: $bar-title-font-size; .icon:before, &.icon:before, &.icon-left:before, &.icon-right:before { font-size: $button-large-icon-size; line-height: $button-bar-button-height; } } &.back-button { display: block; margin-right: 5px; padding: 0; white-space: nowrap; font-weight: 400; } &.back-button.active, &.back-button.activated { opacity: 0.2; } } .button-bar > .button, .buttons > .button { min-height: $button-bar-button-height - 1; line-height: $button-bar-button-height; } .button-bar + .button, .button + .button-bar { margin-left: 5px; } // Android 4.4 messes with the display property .buttons, .buttons.primary-buttons, .buttons.secondary-buttons { display: inherit; } .buttons span { display: inline-block; } .buttons-left span { margin-right: 5px; } .buttons-right span { margin-left: 5px; } // Place the last button in a bar on the right of the bar .title + .button:last-child, > .button + .button:last-child, > .button.pull-right, .buttons.pull-right, .title + .buttons { position: absolute; top: 5px; right: 5px; bottom: 5px; } } .platform-android { .bar { .back-button .icon:before { font-size: 24px; } .title { font-size: 19px; line-height: 43px; } } } // Default styles for buttons inside of styled bars .bar-light { .button { @include button-style($bar-light-bg, $bar-light-border, $bar-light-active-bg, $bar-light-active-border, $bar-light-text); @include button-clear($bar-light-text, $bar-title-font-size); } } .bar-stable { .button { @include button-style($bar-stable-bg, $bar-stable-border, $bar-stable-active-bg, $bar-stable-active-border, $bar-stable-text); @include button-clear($bar-stable-text, $bar-title-font-size); } } .bar-positive { .button { @include button-style($bar-positive-bg, $bar-positive-border, $bar-positive-active-bg, $bar-positive-active-border, $bar-positive-text); @include button-clear(#fff, $bar-title-font-size); } } .bar-calm { .button { @include button-style($bar-calm-bg, $bar-calm-border, $bar-calm-active-bg, $bar-calm-active-border, $bar-calm-text); @include button-clear(#fff, $bar-title-font-size); } } .bar-assertive { .button { @include button-style($bar-assertive-bg, $bar-assertive-border, $bar-assertive-active-bg, $bar-assertive-active-border, $bar-assertive-text); @include button-clear(#fff, $bar-title-font-size); } } .bar-balanced { .button { @include button-style($bar-balanced-bg, $bar-balanced-border, $bar-balanced-active-bg, $bar-balanced-active-border, $bar-balanced-text); @include button-clear(#fff, $bar-title-font-size); } } .bar-energized { .button { @include button-style($bar-energized-bg, $bar-energized-border, $bar-energized-active-bg, $bar-energized-active-border, $bar-energized-text); @include button-clear(#fff, $bar-title-font-size); } } .bar-royal { .button { @include button-style($bar-royal-bg, $bar-royal-border, $bar-royal-active-bg, $bar-royal-active-border, $bar-royal-text); @include button-clear(#fff, $bar-title-font-size); } } .bar-dark { .button { @include button-style($bar-dark-bg, $bar-dark-border, $bar-dark-active-bg, $bar-dark-active-border, $bar-dark-text); @include button-clear(#fff, $bar-title-font-size); } } // Header at top .bar-header { top: 0; border-top-width: 0; border-bottom-width: 1px; &.has-tabs-top{ border-bottom-width: 0px; background-image: none; } } .tabs-top .bar-header{ border-bottom-width: 0px; background-image: none; } // Footer at bottom .bar-footer { bottom: 0; border-top-width: 1px; border-bottom-width: 0; background-position: top; height: $bar-footer-height; &.item-input-inset { position: absolute; } } // Don't render padding if the bar is just for tabs .bar-tabs { padding: 0; } .bar-subheader { top: $bar-height; display: block; height: $bar-subheader-height; } .bar-subfooter { bottom: $bar-footer-height; display: block; height: $bar-subfooter-height; } .nav-bar-block { position: absolute; top: 0; right: 0; left: 0; z-index: $z-index-bar; } .bar .back-button.hide, .bar .buttons .hide { display: none; } ================================================ FILE: server/ionic/scss-live/_button-bar.scss ================================================ /** * Button Bar * -------------------------------------------------- */ .button-bar { @include display-flex(); @include flex(1); width: 100%; &.button-bar-inline { display: block; width: auto; @include clearfix(); > .button { width: auto; display: inline-block; float: left; } } } .button-bar > .button { @include flex(1); display: block; overflow: hidden; padding: 0 16px; width: 0; border-width: 1px 0px 1px 1px; border-radius: 0; text-align: center; text-overflow: ellipsis; white-space: nowrap; &:before, .icon:before { line-height: 44px; } &:first-child { border-radius: $button-border-radius 0px 0px $button-border-radius; } &:last-child { border-right-width: 1px; border-radius: 0px $button-border-radius $button-border-radius 0px; } } ================================================ FILE: server/ionic/scss-live/_button.scss ================================================ /** * Buttons * -------------------------------------------------- */ .button { // set the color defaults @include button-style($button-default-bg, $button-default-border, $button-default-active-bg, $button-default-active-border, $button-default-text); position: relative; display: inline-block; margin: 0; padding: 0 $button-padding; min-width: ($button-padding * 3) + $button-font-size; min-height: $button-height + 5px; border-width: $button-border-width; border-style: solid; border-radius: $button-border-radius; vertical-align: top; text-align: center; text-overflow: ellipsis; font-size: $button-font-size; line-height: $button-height - $button-border-width + 1px; cursor: pointer; &:after { // used to create a larger button "hit" area position: absolute; top: -6px; right: -6px; bottom: -6px; left: -6px; content: ' '; } .icon { vertical-align: top; pointer-events: none; } .icon:before, &.icon:before, &.icon-left:before, &.icon-right:before { display: inline-block; padding: 0 0 $button-border-width 0; vertical-align: inherit; font-size: $button-icon-size; line-height: $button-height - $button-border-width; pointer-events: none; } &.icon-left:before { float: left; padding-right: .2em; padding-left: 0; } &.icon-right:before { float: right; padding-right: 0; padding-left: .2em; } &.button-block, &.button-full { margin-top: $button-block-margin; margin-bottom: $button-block-margin; } &.button-light { @include button-style($button-light-bg, $button-light-border, $button-light-active-bg, $button-light-active-border, $button-light-text); @include button-clear($button-light-border); @include button-outline($button-light-border); } &.button-stable { @include button-style($button-stable-bg, $button-stable-border, $button-stable-active-bg, $button-stable-active-border, $button-stable-text); @include button-clear($button-stable-border); @include button-outline($button-stable-border); } &.button-positive { @include button-style($button-positive-bg, $button-positive-border, $button-positive-active-bg, $button-positive-active-border, $button-positive-text); @include button-clear($button-positive-bg); @include button-outline($button-positive-bg); } &.button-calm { @include button-style($button-calm-bg, $button-calm-border, $button-calm-active-bg, $button-calm-active-border, $button-calm-text); @include button-clear($button-calm-bg); @include button-outline($button-calm-bg); } &.button-assertive { @include button-style($button-assertive-bg, $button-assertive-border, $button-assertive-active-bg, $button-assertive-active-border, $button-assertive-text); @include button-clear($button-assertive-bg); @include button-outline($button-assertive-bg); } &.button-balanced { @include button-style($button-balanced-bg, $button-balanced-border, $button-balanced-active-bg, $button-balanced-active-border, $button-balanced-text); @include button-clear($button-balanced-bg); @include button-outline($button-balanced-bg); } &.button-energized { @include button-style($button-energized-bg, $button-energized-border, $button-energized-active-bg, $button-energized-active-border, $button-energized-text); @include button-clear($button-energized-bg); @include button-outline($button-energized-bg); } &.button-royal { @include button-style($button-royal-bg, $button-royal-border, $button-royal-active-bg, $button-royal-active-border, $button-royal-text); @include button-clear($button-royal-bg); @include button-outline($button-royal-bg); } &.button-dark { @include button-style($button-dark-bg, $button-dark-border, $button-dark-active-bg, $button-dark-active-border, $button-dark-text); @include button-clear($button-dark-bg); @include button-outline($button-dark-bg); } } .button-small { padding: 2px $button-small-padding 1px; min-width: $button-small-height; min-height: $button-small-height + 2; font-size: $button-small-font-size; line-height: $button-small-height - $button-border-width - 1; .icon:before, &.icon:before, &.icon-left:before, &.icon-right:before { font-size: $button-small-icon-size; line-height: $button-small-icon-size + 3; margin-top: 3px; } } .button-large { padding: 0 $button-large-padding; min-width: ($button-large-padding * 3) + $button-large-font-size; min-height: $button-large-height + 5; font-size: $button-large-font-size; line-height: $button-large-height - $button-border-width; .icon:before, &.icon:before, &.icon-left:before, &.icon-right:before { padding-bottom: ($button-border-width * 2); font-size: $button-large-icon-size; line-height: $button-large-height - ($button-border-width * 2) - 1; } } .button-icon { @include transition(opacity .1s); padding: 0 6px; min-width: initial; border-color: transparent; background: none; &.button.active, &.button.activated { border-color: transparent; background: none; box-shadow: none; opacity: 0.3; } .icon:before, &.icon:before { font-size: $button-large-icon-size; } } .button-clear { @include button-clear($button-default-border); @include transition(opacity .1s); padding: 0 $button-clear-padding; max-height: $button-height; border-color: transparent; background: none; box-shadow: none; &.active, &.activated { opacity: 0.3; } } .button-outline { @include button-outline($button-default-border); @include transition(opacity .1s); background: none; box-shadow: none; } .padding > .button.button-block:first-child { margin-top: 0; } .button-block { display: block; clear: both; &:after { clear: both; } } .button-full, .button-full > .button { display: block; margin-right: 0; margin-left: 0; border-right-width: 0; border-left-width: 0; border-radius: 0; } button.button-block, button.button-full, .button-full > button.button, input.button.button-block { width: 100%; } a.button { text-decoration: none; .icon:before, &.icon:before, &.icon-left:before, &.icon-right:before { margin-top: 2px; } } .button.disabled, .button[disabled] { opacity: .4; cursor: default !important; pointer-events: none; } ================================================ FILE: server/ionic/scss-live/_checkbox.scss ================================================ /** * Checkbox * -------------------------------------------------- */ .checkbox { // set the color defaults @include checkbox-style($checkbox-off-border-default, $checkbox-on-bg-default, $checkbox-on-border-default); position: relative; display: inline-block; padding: ($checkbox-height / 4) ($checkbox-width / 4); cursor: pointer; } .checkbox-light { @include checkbox-style($checkbox-off-border-light, $checkbox-on-bg-light, $checkbox-off-border-light); } .checkbox-stable { @include checkbox-style($checkbox-off-border-stable, $checkbox-on-bg-stable, $checkbox-off-border-stable); } .checkbox-positive { @include checkbox-style($checkbox-off-border-positive, $checkbox-on-bg-positive, $checkbox-off-border-positive); } .checkbox-calm { @include checkbox-style($checkbox-off-border-calm, $checkbox-on-bg-calm, $checkbox-off-border-calm); } .checkbox-assertive { @include checkbox-style($checkbox-off-border-assertive, $checkbox-on-bg-assertive, $checkbox-off-border-assertive); } .checkbox-balanced { @include checkbox-style($checkbox-off-border-balanced, $checkbox-on-bg-balanced, $checkbox-off-border-balanced); } .checkbox-energized{ @include checkbox-style($checkbox-off-border-energized, $checkbox-on-bg-energized, $checkbox-off-border-energized); } .checkbox-royal { @include checkbox-style($checkbox-off-border-royal, $checkbox-on-bg-royal, $checkbox-off-border-royal); } .checkbox-dark { @include checkbox-style($checkbox-off-border-dark, $checkbox-on-bg-dark, $checkbox-off-border-dark); } .checkbox input:disabled:before, .checkbox input:disabled + .checkbox-icon:before { border-color: $checkbox-off-border-light; } .checkbox input:disabled:checked:before, .checkbox input:disabled:checked + .checkbox-icon:before { background: $checkbox-on-bg-light; } .checkbox.checkbox-input-hidden input { display: none !important; } .checkbox input, .checkbox-icon { position: relative; width: $checkbox-width; height: $checkbox-height; display: block; border: 0; background: transparent; cursor: pointer; -webkit-appearance: none; &:before { // what the checkbox looks like when its not checked display: table; width: 100%; height: 100%; border-width: $checkbox-border-width; border-style: solid; border-radius: $checkbox-border-radius; background: $checkbox-off-bg-color; content: ' '; @include transition(background-color 20ms ease-in-out); } } .checkbox input:checked:before, input:checked + .checkbox-icon:before { border-width: $checkbox-border-width + 1; } // the checkmark within the box .checkbox input:after, .checkbox-icon:after { @include transition(opacity .05s ease-in-out); @include rotate(-45deg); position: absolute; top: 33%; left: 25%; display: table; width: ($checkbox-width / 2); height: ($checkbox-width / 4) - 1; border: $checkbox-check-width solid $checkbox-check-color; border-top: 0; border-right: 0; content: ' '; opacity: 0; } .platform-android .checkbox-platform input:before, .platform-android .checkbox-platform .checkbox-icon:before, .checkbox-square input:before, .checkbox-square .checkbox-icon:before { border-radius: 2px; width: 72%; height: 72%; margin-top: 14%; margin-left: 14%; border-width: 2px; } .platform-android .checkbox-platform input:after, .platform-android .checkbox-platform .checkbox-icon:after, .checkbox-square input:after, .checkbox-square .checkbox-icon:after { border-width: 2px; top: 19%; left: 25%; width: ($checkbox-width / 2) - 1; height: 7px; } .grade-c .checkbox input:after, .grade-c .checkbox-icon:after { @include rotate(0); top: 3px; left: 4px; border: none; color: $checkbox-check-color; content: '\2713'; font-weight: bold; font-size: 20px; } // what the checkmark looks like when its checked .checkbox input:checked:after, input:checked + .checkbox-icon:after { opacity: 1; } // make sure item content have enough padding on left to fit the checkbox .item-checkbox { padding-left: ($item-padding * 2) + $checkbox-width; &.active { box-shadow: none; } } // position the checkbox to the left within an item .item-checkbox .checkbox { position: absolute; top: 50%; right: $item-padding / 2; left: $item-padding / 2; z-index: $z-index-item-checkbox; margin-top: (($checkbox-height + ($checkbox-height / 2)) / 2) * -1; } .item-checkbox.item-checkbox-right { padding-right: ($item-padding * 2) + $checkbox-width; padding-left: $item-padding; } .item-checkbox-right .checkbox input, .item-checkbox-right .checkbox-icon { float: right; } ================================================ FILE: server/ionic/scss-live/_form.scss ================================================ /** * Forms * -------------------------------------------------- */ // Make all forms have space below them form { margin: 0 0 $line-height-base; } // Groups of fields with labels on top (legends) legend { display: block; margin-bottom: $line-height-base; padding: 0; width: 100%; border: $input-border-width solid $input-border; color: $dark; font-size: $font-size-base * 1.5; line-height: $line-height-base * 2; small { color: $stable; font-size: $line-height-base * .75; } } // Set font for forms label, input, button, select, textarea { @include font-shorthand($font-size-base, normal, $line-height-base); // Set size, weight, line-height here } input, button, select, textarea { font-family: $font-family-base; // And only set font-family here for those that need it (note the missing label element) } // Input List // ------------------------------- .item-input { @include display-flex(); @include align-items(center); position: relative; overflow: hidden; padding: 6px 0 5px 16px; input { @include border-radius(0); @include flex(1, 0, 220px); @include appearance(none); margin: 0; padding-right: 24px; background-color: transparent; } .button .icon { @include flex(0, 0, 24px); position: static; display: inline-block; height: auto; text-align: center; font-size: 16px; } .button-bar { @include border-radius(0); @include flex(1, 0, 220px); @include appearance(none); } .icon { min-width: 14px; } } .item-input-inset { @include display-flex(); @include align-items(center); position: relative; overflow: hidden; padding: ($item-padding / 3) * 2; } .item-input-wrapper { @include display-flex(); @include flex(1, 0); @include align-items(center); @include border-radius(4px); padding-right: 8px; padding-left: 8px; background: #eee; } .item-input-inset .item-input-wrapper input { padding-left: 4px; height: 29px; background: transparent; line-height: 18px; } .item-input-wrapper ~ .button { margin-left: ($item-padding / 3) * 2; } .input-label { @include flex(1, 0, 100px); display: table; padding: 7px 10px 7px 0px; max-width: 200px; width: 35%; color: $input-label-color; font-size: 16px; } .placeholder-icon { color: #aaa; &:first-child { padding-right: 6px; } &:last-child { padding-left: 6px; } } .item-stacked-label { display: block; background-color: transparent; box-shadow: none; .input-label, .icon { display: inline-block; padding: 4px 0 0 0px; vertical-align: middle; } } .item-stacked-label input, .item-stacked-label textarea { @include border-radius(2px); padding: 4px 8px 3px 0; border: none; background-color: $input-bg; } .item-stacked-label input { overflow: hidden; height: $line-height-computed + $font-size-base + 12px; } .item-floating-label { display: block; background-color: transparent; box-shadow: none; .input-label { position: relative; padding: 5px 0 0 0; opacity: 0; top: 10px; @include transition(opacity .15s ease-in, top .2s linear); &.has-input { opacity: 1; top: 0; @include transition(opacity .15s ease-in, top .2s linear); } } } // Form Controls // ------------------------------- // Shared size and type resets textarea, input[type="text"], input[type="password"], input[type="datetime"], input[type="datetime-local"], input[type="date"], input[type="month"], input[type="time"], input[type="week"], input[type="number"], input[type="email"], input[type="url"], input[type="search"], input[type="tel"], input[type="color"] { display: block; padding-top: 2px; padding-left: 0; height: $line-height-computed + $font-size-base; color: $input-color; vertical-align: middle; font-size: $font-size-base; line-height: $font-size-base + 2; } .platform-ios, .platform-android { input[type="datetime-local"], input[type="date"], input[type="month"], input[type="time"], input[type="week"] { padding-top: 8px; } } input, textarea { width: 100%; } textarea { padding-left: 0; @include placeholder($input-color-placeholder, -3px); } // Reset height since textareas have rows textarea { height: auto; } // Everything else textarea, input[type="text"], input[type="password"], input[type="datetime"], input[type="datetime-local"], input[type="date"], input[type="month"], input[type="time"], input[type="week"], input[type="number"], input[type="email"], input[type="url"], input[type="search"], input[type="tel"], input[type="color"] { border: 0; } // Position radios and checkboxes better input[type="radio"], input[type="checkbox"] { margin: 0; line-height: normal; } // Reset width of input images, buttons, radios, checkboxes input[type="file"], input[type="image"], input[type="submit"], input[type="reset"], input[type="button"], input[type="radio"], input[type="checkbox"] { width: auto; // Override of generic input selector } // Set the height of file to match text inputs input[type="file"] { line-height: $input-height-base; } // Text input classes to hide text caret during scroll .previous-input-focus, .cloned-text-input + input, .cloned-text-input + textarea { position: absolute !important; left: -9999px; width: 200px; } // Placeholder // ------------------------------- input, textarea { @include placeholder(); } // DISABLED STATE // ------------------------------- // Disabled and read-only inputs input[disabled], select[disabled], textarea[disabled], input[readonly]:not(.cloned-text-input), textarea[readonly]:not(.cloned-text-input), select[readonly] { background-color: $input-bg-disabled; cursor: not-allowed; } // Explicitly reset the colors here input[type="radio"][disabled], input[type="checkbox"][disabled], input[type="radio"][readonly], input[type="checkbox"][readonly] { background-color: transparent; } ================================================ FILE: server/ionic/scss-live/_grid.scss ================================================ /** * Grid * -------------------------------------------------- * Using flexbox for the grid, inspired by Philip Walton: * http://philipwalton.github.io/solved-by-flexbox/demos/grids/ * By default each .col within a .row will evenly take up * available width, and the height of each .col with take * up the height of the tallest .col in the same .row. */ .row { @include display-flex(); padding: ($grid-padding-width / 2); width: 100%; } .row-wrap { @include flex-wrap(wrap); } .row + .row { margin-top: ($grid-padding-width / 2) * -1; padding-top: 0; } .col { @include flex(1); display: block; padding: ($grid-padding-width / 2); width: 100%; } /* Vertically Align Columns */ /* .row-* vertically aligns every .col in the .row */ .row-top { @include align-items(flex-start); } .row-bottom { @include align-items(flex-end); } .row-center { @include align-items(center); } .row-stretch { @include align-items(stretch); } .row-baseline { @include align-items(baseline); } /* .col-* vertically aligns an individual .col */ .col-top { @include align-self(flex-start); } .col-bottom { @include align-self(flex-end); } .col-center { @include align-self(center); } /* Column Offsets */ .col-offset-10 { margin-left: 10%; } .col-offset-20 { margin-left: 20%; } .col-offset-25 { margin-left: 25%; } .col-offset-33, .col-offset-34 { margin-left: 33.3333%; } .col-offset-50 { margin-left: 50%; } .col-offset-66, .col-offset-67 { margin-left: 66.6666%; } .col-offset-75 { margin-left: 75%; } .col-offset-80 { margin-left: 80%; } .col-offset-90 { margin-left: 90%; } /* Explicit Column Percent Sizes */ /* By default each grid column will evenly distribute */ /* across the grid. However, you can specify individual */ /* columns to take up a certain size of the available area */ .col-10 { @include flex(0, 0, 10%); max-width: 10%; } .col-20 { @include flex(0, 0, 20%); max-width: 20%; } .col-25 { @include flex(0, 0, 25%); max-width: 25%; } .col-33, .col-34 { @include flex(0, 0, 33.3333%); max-width: 33.3333%; } .col-50 { @include flex(0, 0, 50%); max-width: 50%; } .col-66, .col-67 { @include flex(0, 0, 66.6666%); max-width: 66.6666%; } .col-75 { @include flex(0, 0, 75%); max-width: 75%; } .col-80 { @include flex(0, 0, 80%); max-width: 80%; } .col-90 { @include flex(0, 0, 90%); max-width: 90%; } /* Responsive Grid Classes */ /* Adding a class of responsive-X to a row */ /* will trigger the flex-direction to */ /* change to column and add some margin */ /* to any columns in the row for clearity */ @include responsive-grid-break('.responsive-sm', $grid-responsive-sm-break); @include responsive-grid-break('.responsive-md', $grid-responsive-md-break); @include responsive-grid-break('.responsive-lg', $grid-responsive-lg-break); ================================================ FILE: server/ionic/scss-live/_items.scss ================================================ /** * Items * -------------------------------------------------- */ .item { @include item-style($item-default-bg, $item-default-border, $item-default-text); position: relative; z-index: $z-index-item; // Make sure the borders and stuff don't get hidden by children display: block; margin: $item-border-width * -1; padding: $item-padding; border-width: $item-border-width; border-style: solid; font-size: $item-font-size; h2 { margin: 0 0 2px 0; font-size: 16px; font-weight: normal; } h3 { margin: 0 0 4px 0; font-size: 14px; } h4 { margin: 0 0 4px 0; font-size: 12px; } h5, h6 { margin: 0 0 3px 0; font-size: 10px; } p { color: #666; font-size: 14px; margin-bottom: 2px; } h1:last-child, h2:last-child, h3:last-child, h4:last-child, h5:last-child, h6:last-child, p:last-child { margin-bottom: 0; } // Align badges within items .badge { @include display-flex(); position: absolute; top: $item-padding; right: ($item-padding * 2); } &.item-button-right .badge { right: ($item-padding * 2) + 35; } &.item-divider .badge { top: ceil($item-padding / 2); } .badge + .badge { margin-right: 5px; } // Different themes for items &.item-light { @include item-style($item-light-bg, $item-light-border, $item-light-text); } &.item-stable { @include item-style($item-stable-bg, $item-stable-border, $item-stable-text); } &.item-positive { @include item-style($item-positive-bg, $item-positive-border, $item-positive-text); } &.item-calm { @include item-style($item-calm-bg, $item-calm-border, $item-calm-text); } &.item-assertive { @include item-style($item-assertive-bg, $item-assertive-border, $item-assertive-text); } &.item-balanced { @include item-style($item-balanced-bg, $item-balanced-border, $item-balanced-text); } &.item-energized { @include item-style($item-energized-bg, $item-energized-border, $item-energized-text); } &.item-royal { @include item-style($item-royal-bg, $item-royal-border, $item-royal-text); } &.item-dark { @include item-style($item-dark-bg, $item-dark-border, $item-dark-text); } &[ng-click]:hover { cursor: pointer; } } .list-borderless .item, .item-borderless { border-width: 0; } // Link and Button Active States .item.active, .item.activated, .item-complex.active .item-content, .item-complex.activated .item-content, .item .item-content.active, .item .item-content.activated { @include item-active-style($item-default-active-bg, $item-default-active-border); // Different active themes for and