├── www
└── .gitkeep
├── app
├── config.js
├── components
│ ├── index.js
│ ├── ui
│ │ ├── loading
│ │ │ ├── spinner.scss
│ │ │ ├── loading.html
│ │ │ └── index.js
│ │ ├── subheader_pane
│ │ │ ├── subheader_pane.html
│ │ │ ├── subheader_pane_content.html
│ │ │ ├── index.js
│ │ │ ├── show_subheader_pane_directive.js
│ │ │ ├── subheader_pane.scss
│ │ │ ├── subheader_pane_content_directive.js
│ │ │ └── subheader_pane_directive.js
│ │ ├── fake_tabs
│ │ │ ├── fake_tabs.html
│ │ │ ├── fake_tab.html
│ │ │ └── index.js
│ │ ├── shrinkable_image_header
│ │ │ ├── shrinkable_image_header.html
│ │ │ ├── index.js
│ │ │ └── directive.js
│ │ ├── static_map
│ │ │ ├── static_map.html
│ │ │ ├── static_map.scss
│ │ │ └── index.js
│ │ └── view_switching
│ │ │ └── index.js
│ ├── views
│ │ ├── google_images
│ │ │ ├── google_images.jade
│ │ │ ├── controllers
│ │ │ │ └── google_images_controller.js
│ │ │ └── index.js
│ │ ├── index.js
│ │ └── tabs.jade
│ ├── utils
│ │ ├── default_route
│ │ │ └── index.js
│ │ └── cached_image_loader
│ │ │ └── index.js
│ ├── data
│ │ ├── google_images
│ │ │ └── index.js
│ │ └── store
│ │ │ └── index.js
│ └── bootstrap.js
├── templates.js
├── env
│ ├── development.js
│ └── production.js
├── fonts
│ ├── -DackuIFgo7Hfy3rR14C34X0hVgzZQUfRDuZrPvH3D8.woff2
│ ├── Be0CkOtwwI2n86HMhtablYX0hVgzZQUfRDuZrPvH3D8.woff2
│ ├── UgYUhLCkRUocJ8OZnvelZ4X0hVgzZQUfRDuZrPvH3D8.woff2
│ ├── fND5XPYKrF2tQDwwfWZJI4joYw3YTyktCCer_ilOlhE.woff2
│ ├── fND5XPYKrF2tQDwwfWZJI_y1_HTwRwgtl1cPga3Fy3Y.woff2
│ ├── fND5XPYKrF2tQDwwfWZJIw7aC6SjiAOpAWOKfJDfVRY.woff2
│ ├── fND5XPYKrF2tQDwwfWZJIxampu5_7CjHW5spxoeN3Vs.woff2
│ ├── fND5XPYKrF2tQDwwfWZJIxdwxCXfZpKo5kWAx_74bHs.woff2
│ ├── qLBu5CQmSMt1H43OiWJ77ZBw1xU1rKptJj_0jans920.woff2
│ ├── r_tUZNl0G8xCoOmp_JkSCg7aC6SjiAOpAWOKfJDfVRY.woff2
│ ├── r_tUZNl0G8xCoOmp_JkSChampu5_7CjHW5spxoeN3Vs.woff2
│ ├── r_tUZNl0G8xCoOmp_JkSChdwxCXfZpKo5kWAx_74bHs.woff2
│ ├── r_tUZNl0G8xCoOmp_JkSCojoYw3YTyktCCer_ilOlhE.woff2
│ ├── r_tUZNl0G8xCoOmp_JkSCvy1_HTwRwgtl1cPga3Fy3Y.woff2
│ ├── wz1gqe57Mbg11v-OrLlVjoX0hVgzZQUfRDuZrPvH3D8.woff2
│ └── qLBu5CQmSMt1H43OiWJ77ZBw1xU1rKptJj_0jans920 (1).woff2
├── _variables.scss
├── index.scss
├── index.html
├── index.js
├── jqlite_animate_comment_patch.js
└── fonts.scss
├── ionic.project
├── dev-server
├── .gitignore
├── .editorconfig
├── bower.json
├── config.xml
├── README.md
├── package.json
├── hooks
├── after_prepare
│ └── 010_add_platform_class.js
└── README.md
├── gulpfile.js
└── webpack.config.js
/www/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/config.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = {
4 | };
5 |
--------------------------------------------------------------------------------
/app/components/index.js:
--------------------------------------------------------------------------------
1 | var App = angular.module('app', [
2 | require('./utils/default_route')
3 | ]);
--------------------------------------------------------------------------------
/app/templates.js:
--------------------------------------------------------------------------------
1 | var TemplatesModule = angular.module('templates', []);
2 | module.exports = TemplatesModule.name;
3 |
--------------------------------------------------------------------------------
/ionic.project:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ionic-webpack",
3 | "app_id": "",
4 | "gulpStartupTasks": [
5 | "watch"
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/app/components/ui/loading/spinner.scss:
--------------------------------------------------------------------------------
1 | .spinner.spinner-large {
2 | svg {
3 | width: 48px;
4 | height: 48px;
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/app/components/ui/subheader_pane/subheader_pane.html:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/components/ui/subheader_pane/subheader_pane_content.html:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/dev-server:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | webpack-dev-server --content-base www/ -devtool eval-source-map --port 5000 --hot --inline --colors --history-api-fallback
3 |
--------------------------------------------------------------------------------
/app/components/ui/fake_tabs/fake_tabs.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/env/development.js:
--------------------------------------------------------------------------------
1 | var EnvironmentModule = angular.module('environment', [])
2 | .config(function ($logProvider){
3 | });
4 |
5 | module.exports = EnvironmentModule.name;
6 |
--------------------------------------------------------------------------------
/app/env/production.js:
--------------------------------------------------------------------------------
1 | var EnvironmentModule = angular.module('environment', [])
2 | .config(function ($logProvider){
3 | });
4 |
5 | module.exports = EnvironmentModule.name;
6 |
--------------------------------------------------------------------------------
/app/fonts/-DackuIFgo7Hfy3rR14C34X0hVgzZQUfRDuZrPvH3D8.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AMar4enko/ionic-webpack-starter/HEAD/app/fonts/-DackuIFgo7Hfy3rR14C34X0hVgzZQUfRDuZrPvH3D8.woff2
--------------------------------------------------------------------------------
/app/fonts/Be0CkOtwwI2n86HMhtablYX0hVgzZQUfRDuZrPvH3D8.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AMar4enko/ionic-webpack-starter/HEAD/app/fonts/Be0CkOtwwI2n86HMhtablYX0hVgzZQUfRDuZrPvH3D8.woff2
--------------------------------------------------------------------------------
/app/fonts/UgYUhLCkRUocJ8OZnvelZ4X0hVgzZQUfRDuZrPvH3D8.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AMar4enko/ionic-webpack-starter/HEAD/app/fonts/UgYUhLCkRUocJ8OZnvelZ4X0hVgzZQUfRDuZrPvH3D8.woff2
--------------------------------------------------------------------------------
/app/fonts/fND5XPYKrF2tQDwwfWZJI4joYw3YTyktCCer_ilOlhE.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AMar4enko/ionic-webpack-starter/HEAD/app/fonts/fND5XPYKrF2tQDwwfWZJI4joYw3YTyktCCer_ilOlhE.woff2
--------------------------------------------------------------------------------
/app/fonts/fND5XPYKrF2tQDwwfWZJI_y1_HTwRwgtl1cPga3Fy3Y.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AMar4enko/ionic-webpack-starter/HEAD/app/fonts/fND5XPYKrF2tQDwwfWZJI_y1_HTwRwgtl1cPga3Fy3Y.woff2
--------------------------------------------------------------------------------
/app/fonts/fND5XPYKrF2tQDwwfWZJIw7aC6SjiAOpAWOKfJDfVRY.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AMar4enko/ionic-webpack-starter/HEAD/app/fonts/fND5XPYKrF2tQDwwfWZJIw7aC6SjiAOpAWOKfJDfVRY.woff2
--------------------------------------------------------------------------------
/app/fonts/fND5XPYKrF2tQDwwfWZJIxampu5_7CjHW5spxoeN3Vs.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AMar4enko/ionic-webpack-starter/HEAD/app/fonts/fND5XPYKrF2tQDwwfWZJIxampu5_7CjHW5spxoeN3Vs.woff2
--------------------------------------------------------------------------------
/app/fonts/fND5XPYKrF2tQDwwfWZJIxdwxCXfZpKo5kWAx_74bHs.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AMar4enko/ionic-webpack-starter/HEAD/app/fonts/fND5XPYKrF2tQDwwfWZJIxdwxCXfZpKo5kWAx_74bHs.woff2
--------------------------------------------------------------------------------
/app/fonts/qLBu5CQmSMt1H43OiWJ77ZBw1xU1rKptJj_0jans920.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AMar4enko/ionic-webpack-starter/HEAD/app/fonts/qLBu5CQmSMt1H43OiWJ77ZBw1xU1rKptJj_0jans920.woff2
--------------------------------------------------------------------------------
/app/fonts/r_tUZNl0G8xCoOmp_JkSCg7aC6SjiAOpAWOKfJDfVRY.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AMar4enko/ionic-webpack-starter/HEAD/app/fonts/r_tUZNl0G8xCoOmp_JkSCg7aC6SjiAOpAWOKfJDfVRY.woff2
--------------------------------------------------------------------------------
/app/fonts/r_tUZNl0G8xCoOmp_JkSChampu5_7CjHW5spxoeN3Vs.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AMar4enko/ionic-webpack-starter/HEAD/app/fonts/r_tUZNl0G8xCoOmp_JkSChampu5_7CjHW5spxoeN3Vs.woff2
--------------------------------------------------------------------------------
/app/fonts/r_tUZNl0G8xCoOmp_JkSChdwxCXfZpKo5kWAx_74bHs.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AMar4enko/ionic-webpack-starter/HEAD/app/fonts/r_tUZNl0G8xCoOmp_JkSChdwxCXfZpKo5kWAx_74bHs.woff2
--------------------------------------------------------------------------------
/app/fonts/r_tUZNl0G8xCoOmp_JkSCojoYw3YTyktCCer_ilOlhE.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AMar4enko/ionic-webpack-starter/HEAD/app/fonts/r_tUZNl0G8xCoOmp_JkSCojoYw3YTyktCCer_ilOlhE.woff2
--------------------------------------------------------------------------------
/app/fonts/r_tUZNl0G8xCoOmp_JkSCvy1_HTwRwgtl1cPga3Fy3Y.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AMar4enko/ionic-webpack-starter/HEAD/app/fonts/r_tUZNl0G8xCoOmp_JkSCvy1_HTwRwgtl1cPga3Fy3Y.woff2
--------------------------------------------------------------------------------
/app/fonts/wz1gqe57Mbg11v-OrLlVjoX0hVgzZQUfRDuZrPvH3D8.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AMar4enko/ionic-webpack-starter/HEAD/app/fonts/wz1gqe57Mbg11v-OrLlVjoX0hVgzZQUfRDuZrPvH3D8.woff2
--------------------------------------------------------------------------------
/app/components/ui/loading/loading.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/fonts/qLBu5CQmSMt1H43OiWJ77ZBw1xU1rKptJj_0jans920 (1).woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AMar4enko/ionic-webpack-starter/HEAD/app/fonts/qLBu5CQmSMt1H43OiWJ77ZBw1xU1rKptJj_0jans920 (1).woff2
--------------------------------------------------------------------------------
/app/components/ui/shrinkable_image_header/shrinkable_image_header.html:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/_variables.scss:
--------------------------------------------------------------------------------
1 | $font-family-sans-serif: 'Comfortaa', 'Helvetica Neue', 'Roboto', sans-serif !default;
2 | $font-family-light-sans-serif: 'Comfortaa', 'HelveticaNeue-Light', 'Roboto-Light', sans-serif-light !default;
--------------------------------------------------------------------------------
/app/index.scss:
--------------------------------------------------------------------------------
1 | @import "./variables";
2 | @import "./fonts";
3 |
4 | // The path for our ionicons font files, relative to the built CSS in www/css
5 | $ionicons-font-path: "../bower_components/ionic/fonts" !default;
6 | @import "ionic/scss/ionic";
7 |
--------------------------------------------------------------------------------
/app/components/ui/static_map/static_map.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
![]()
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/components/ui/fake_tabs/fake_tab.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Specifies intentionally untracked files to ignore when using Git
2 | # http://git-scm.com/docs/gitignore
3 |
4 | bower_components/
5 | node_modules/
6 | platforms/
7 | plugins/
8 | .tmp/
9 | .sass-cache/
10 | .DS_Store
11 | /.idea
12 | /engine
13 | *.log
14 |
--------------------------------------------------------------------------------
/app/components/ui/shrinkable_image_header/index.js:
--------------------------------------------------------------------------------
1 | var ShrinkableImageHeader = angular.module('app.ui.shrinkableImageHeader', []);
2 |
3 | module.exports = ShrinkableImageHeader.name;
4 |
5 | ShrinkableImageHeader.directive('shrinkableImageHeader', require('./directive'));
6 |
7 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | charset = utf-8
9 | trim_trailing_whitespace = true
10 | insert_final_newline = true
11 |
12 | [*.md]
13 | trim_trailing_whitespace = false
14 |
--------------------------------------------------------------------------------
/app/components/views/google_images/google_images.jade:
--------------------------------------------------------------------------------
1 | ion-view(title="Google Images test")
2 | ion-content
3 | ion-list
4 | ion-item(collection-repeat="image in googleImages.items" class="item-avatar")
5 | img(ng-src="{{image.tbUrl}}")
6 | h2(ng-bind="image.titleNoFormatting")
7 | p(ng-bind="image.contentNoFormatting")
8 |
--------------------------------------------------------------------------------
/app/components/views/google_images/controllers/google_images_controller.js:
--------------------------------------------------------------------------------
1 | module.exports = GoogleImagesController;
2 |
3 | function GoogleImagesController (GoogleImages){
4 | var vm = this;
5 | GoogleImages.findAll({q: 'habrahabr', start: 0, rsz: 8}).then(function (items){
6 | vm.items = items;
7 | });
8 | }
9 |
10 | GoogleImagesController.resolve = {
11 |
12 | };
--------------------------------------------------------------------------------
/app/components/utils/default_route/index.js:
--------------------------------------------------------------------------------
1 | var DefaultRouteModule = angular.module('app.utils.defaultRoute', ['ionic', 'ui.router']);
2 |
3 | module.exports = DefaultRouteModule.name;
4 |
5 | DefaultRouteModule.config(function ($urlRouterProvider){
6 | $urlRouterProvider.otherwise(defaultUrl);
7 |
8 | function defaultUrl ($inject){
9 | return $location.replace().url('/signin');
10 | }
11 | });
12 |
--------------------------------------------------------------------------------
/app/components/ui/static_map/static_map.scss:
--------------------------------------------------------------------------------
1 | @import '../../../../bower_components/bourbon/app/assets/stylesheets/bourbon';
2 |
3 | .static-map {
4 | .img-wrap {
5 | opacity: 0;
6 | }
7 | &.loading {
8 | .img-wrap {
9 | opacity: 0;
10 | @include transition(all 0.3s ease-in-out);
11 | }
12 | }
13 |
14 | &.loaded {
15 | .img-wrap {
16 | opacity: 1;
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/app/components/ui/subheader_pane/index.js:
--------------------------------------------------------------------------------
1 | var SubheaderSlider = angular.module('app.ui.subheaderSlider', []);
2 |
3 | module.exports = SubheaderSlider.name;
4 |
5 | require('./subheader_pane.scss');
6 |
7 | SubheaderSlider.directive('subheaderPane', require('./subheader_pane_directive'));
8 | SubheaderSlider.directive('showSubheaderPane', require('./show_subheader_pane_directive'));
9 | SubheaderSlider.directive('subheaderPaneContent', require('./subheader_pane_content_directive'));
10 |
--------------------------------------------------------------------------------
/app/components/ui/subheader_pane/show_subheader_pane_directive.js:
--------------------------------------------------------------------------------
1 | module.exports = ShowSubheaderPaneDirectiveProvider;
2 |
3 | function ShowSubheaderPaneDirectiveProvider (){
4 | return {
5 | restrict: 'A',
6 | require: '^subheaderPane',
7 | link: function ($scope, iElem, iAttrs, subheaderPane){
8 | iElem.bind('click', function (event){
9 | $scope.$apply(function (){
10 | subheaderPane.showHide(iAttrs.showSubheaderPane && $scope.$eval(iAttrs.showSubheaderPane));
11 | });
12 | });
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/app/components/data/google_images/index.js:
--------------------------------------------------------------------------------
1 | var GoogleImagesData = angular.module('app.data.googleImages', [
2 | require('../store')
3 | ]);
4 |
5 | module.exports = GoogleImagesData.name;
6 |
7 | var imageResource;
8 |
9 | GoogleImagesData.run(function (DataStore){
10 | imageResource = DataStore.defineResource({
11 | name: 'GoogleImage',
12 | basePath: 'http://ajax.googleapis.com/ajax/services/search',
13 | endpoint: '/images?v=1.0',
14 | idAttribute: 'imageId'
15 | });
16 | });
17 |
18 | GoogleImagesData.factory('GoogleImages', function (){
19 | return imageResource;
20 | });
--------------------------------------------------------------------------------
/app/components/views/index.js:
--------------------------------------------------------------------------------
1 | var Views = angular.module('app.views', [
2 | require('./google_images'),
3 | require('../ui/fake_tabs')
4 | ]);
5 | var slideMenuTemplate = require('./tabs.jade');
6 |
7 | module.exports = Views.name;
8 |
9 | Views.config(function ($stateProvider){
10 | $stateProvider.state(
11 | 'app',
12 | {
13 | url: '',
14 | abstract: true
15 | }
16 | ).state(
17 | 'app.tabs',
18 | {
19 | url: '/tabs',
20 | abstract: true,
21 | views: {
22 | '@': {
23 | templateUrl: slideMenuTemplate
24 | }
25 | }
26 | }
27 | );
28 | });
29 |
--------------------------------------------------------------------------------
/app/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | {%= o.htmlWebpackPlugin.options.title || o.htmlWebpackPlugin.options.pkg.name || 'Webpack App'%}
8 |
9 |
10 |
11 |
12 | {% for (var chunk in o.htmlWebpackPlugin.assets) { %}{% } %}
13 |
14 |
15 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ionic-webpack",
3 | "version": "0.0.1",
4 | "dependencies": {
5 | "ionic": "git@github.com:driftyco/ionic-bower.git#1.0.0-rc.1-nightly-1153",
6 | "angular": "1.3.15",
7 | "angular-animate": "~1.3.15",
8 | "angular-sanitize": "~1.3.15",
9 | "angular-ui-router": "0.2.13",
10 | "angular-cache": "~3.2.5",
11 | "auth0-angular": "~4.0.1",
12 | "ngstorage": "~0.3.0",
13 | "lodash": "~3.5.0",
14 | "selfish": "~0.3.3",
15 | "bourbon": "~4.2.1",
16 | "imgcache.js": "~0.7.6"
17 | },
18 | "resolutions": {
19 | "angular-animate": "~1.3.15",
20 | "angular-sanitize": "~1.3.15",
21 | "angular": "1.3.13",
22 | "lodash": "~3.5.0"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/app/components/data/store/index.js:
--------------------------------------------------------------------------------
1 | var DataStore = angular.module('app.data.store', ['js-data']);
2 |
3 | module.exports = DataStore.name;
4 |
5 | DataStore
6 | .provider('DataStore', function (DSProvider){
7 | return DSProvider;
8 | })
9 | .config(function (DataStoreProvider, DSHttpAdapterProvider){
10 | DSHttpAdapterProvider.defaults = {
11 | deserialize: function (config, response){
12 | if(config.class == 'GoogleImage'){
13 | return response.data.responseData.results;
14 | }
15 | return data;
16 | }
17 | };
18 | DataStoreProvider.defaults.basePath = 'some.endpoint/';
19 | })
20 | .run(function (DataStore, DSHttpAdapter){
21 | DataStore.registerAdapter('http', DSHttpAdapter, { default: true });
22 | });
23 |
--------------------------------------------------------------------------------
/app/components/ui/subheader_pane/subheader_pane.scss:
--------------------------------------------------------------------------------
1 | @import './variables';
2 |
3 | .subheader-pane {
4 | z-index: 11 !important;
5 | &.has-tabs-top.has-subheader {
6 | top: 137px;
7 | }
8 | &.has-subheader {
9 | top: 88px;
10 | }
11 | }
12 |
13 | .pane-backdrop {
14 | &:after{
15 | content: " ";
16 | display: block;
17 | position: absolute;
18 | left: 0; top: 0;
19 | right: 0; bottom: 0;
20 | visibility: visible;
21 | opacity: 0;
22 | background-color: black;
23 | z-index: 3;
24 | transition: opacity 0.6s ease-out;
25 | -webkit-transition: opacity 0.6s ease-out;
26 | pointer-events: none;
27 | }
28 | &.pane-backdrop-visible {
29 | &:after {
30 | //visibility: visible;
31 | opacity: 0.8;
32 | }
33 | }
34 | }
35 |
36 |
37 |
--------------------------------------------------------------------------------
/app/components/views/google_images/index.js:
--------------------------------------------------------------------------------
1 | var GoogleImages = angular.module('app.views.googleImages', [
2 | require('../../data/google_images')
3 | ]);
4 |
5 | var GoogleImagesController = require('./controllers/google_images_controller');
6 | var template = require('./google_images.jade');
7 |
8 | module.exports = GoogleImages.name;
9 |
10 | GoogleImages.controller('GoogleImagesController', GoogleImagesController);
11 |
12 | GoogleImages.config(function ($stateProvider){
13 | $stateProvider.state(
14 | 'app.tabs.googleImages',
15 | {
16 | url: '/google-images',
17 | resolve: GoogleImagesController.resolve,
18 | views: {
19 | '@app.tabs': {
20 | templateUrl: template,
21 | controller: 'GoogleImagesController as googleImages'
22 | }
23 | }
24 | }
25 | )
26 | });
--------------------------------------------------------------------------------
/app/components/views/tabs.jade:
--------------------------------------------------------------------------------
1 | ion-side-menus
2 | ion-side-menu-content
3 | ion-nav-bar.bar.bar-royal(align-title='center')
4 | ion-nav-back-button
5 | ion-nav-buttons(side='left')
6 | button.button.button-icon.button-clear.ion-navicon(menu-toggle='left')
7 |
8 | ion-nav-title App
9 | ion-pane
10 | ion-fake-tabs(background='royal', color='light')
11 | ion-fake-tab(sref='app.tabs.googleImages', icon='ion-android-image', root='true')
12 | ion-fake-tab(sref='app.tabs.test1', icon='ion-android-happy', root='true')
13 | ion-fake-tab(sref='app.tabs.test2', icon='ion-android-bulb', root='true')
14 | ion-nav-view(animation='slide-left-right')
15 |
16 | ion-side-menu.dark-bg.dark-border(side='left', expose-aside-when='large')
17 | ion-header-bar.bar-dark
18 | h1.title Side menu
19 | ion-content.has-header
20 | ion-list
21 | ion-item Menu item
22 |
--------------------------------------------------------------------------------
/app/components/ui/loading/index.js:
--------------------------------------------------------------------------------
1 | require('./spinner.scss');
2 |
3 | var Loading = angular.module('app.ui.loading', []);
4 | var loadingTemplateUrl = require('./loading.html');
5 |
6 | module.exports = Loading.name;
7 |
8 | Loading.factory('LoadingPopup', LoadingPopupFactory);
9 |
10 | Loading.run(function ($rootScope, $ionicLoading){
11 | $rootScope.$on('$stateChangeError', $ionicLoading.hide.bind($ionicLoading));
12 | });
13 |
14 | /**
15 | * @ngInject
16 | * @constructor
17 | * @param $ionicLoading
18 | * @param $rootScope
19 | * @param $sce
20 | */
21 | function LoadingPopupFactory ($ionicLoading, $rootScope, $sce){
22 | var loadingScope = $rootScope.$new(true);
23 |
24 | return function (loadingMessage){
25 | loadingScope.$message = $sce.trustAsHtml(loadingMessage);
26 | $ionicLoading.show({
27 | templateUrl: loadingTemplateUrl,
28 | hideOnStateChange: true,
29 | scope: loadingScope
30 | });
31 |
32 | return function (){
33 | $ionicLoading.hide();
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/app/components/ui/view_switching/index.js:
--------------------------------------------------------------------------------
1 | var ViewSwitching = angular.module('app.ui.view-switching', [
2 | require('../loading')
3 | ]);
4 | var _ = require('lodash');
5 |
6 | module.exports = ViewSwitching.name;
7 |
8 | ViewSwitching.service('ViewSwitching', ViewSwitchingService);
9 |
10 | function ViewSwitchingService ($state, $ionicViewSwitcher, $ionicHistory, LoadingPopup){
11 | this.goTo = goToState;
12 |
13 | function goToState (newState, params, direction, options){
14 | direction = direction || 'forward';
15 | options = options || {};
16 |
17 |
18 | if($state.current.name == newState){
19 | if(!params || _.isEmpty(params)){
20 | return;
21 | }
22 | }
23 |
24 | if(options.root){
25 | $ionicHistory.nextViewOptions({
26 | historyRoot: true
27 | });
28 | }
29 |
30 | if(direction){
31 | $ionicViewSwitcher.nextDirection(direction);
32 | }
33 |
34 | LoadingPopup(options.popupText || 'Loading');
35 |
36 | $state.go(newState, params);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/app/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var
4 | angular = require('angular'),
5 | templates = require('./templates'),
6 | bootstrap = require('./components/bootstrap');
7 |
8 | var appModule = module.exports = angular
9 | .module('ionic-webpack', [
10 | bootstrap.name,
11 | require('angular-router-exception-handler'),
12 | require('./env/'+NODE_ENV),
13 | require('./components/views'),
14 | templates
15 | ])
16 | .constant('version', require('../package.json').version)
17 | .constant('config', require('./config'))
18 | .config(function ($compileProvider) {
19 | $compileProvider.imgSrcSanitizationWhitelist(/^\s*(https?|local|data|filesystem|file):/);
20 | $compileProvider.aHrefSanitizationWhitelist(
21 | /^\s*(https?|ftp|mailto|file|tel):/);
22 | });
23 |
24 | // Add the styles to the page
25 | require('./index.scss');
26 |
27 | // Patching angular + angular-animate error with transcluding comment element
28 | require('./jqlite_animate_comment_patch')(angular.element);
29 |
30 | bootstrap.ionicBootstrap(appModule, global, {
31 | fonts: ['Comfortaa']
32 | });
33 |
34 |
--------------------------------------------------------------------------------
/app/components/utils/cached_image_loader/index.js:
--------------------------------------------------------------------------------
1 | var ImgCache = require('imgcache.js');
2 | var CachedImageLoader = angular.module('app.utils.cachedImageLoader', []);
3 |
4 | module.exports = CachedImageLoader.name;
5 |
6 | CachedImageLoader.factory('CachedImageLoader', function($q){
7 | var initDefer = $q.defer();
8 | ImgCache.options.debug = true;
9 | ImgCache.options.chromeQuota = 50*1024*1024;
10 | ImgCache.init(initDefer.resolve, initDefer.reject);
11 | return function(src){
12 | return initDefer.promise.then(function(){
13 | var defer = $q.defer();
14 | ImgCache.isCached(src, function(_src, cached){
15 | if(cached){
16 | ImgCache.getCachedFileURL(src, function(originalUrl, cachedFileUrl){
17 | defer.resolve(cachedFileUrl);
18 | }, defer.reject);
19 | return;
20 | }
21 | ImgCache.cacheFile(src, function(){
22 | ImgCache.getCachedFileURL(src, function(originalUrl, cachedFileUrl){
23 | defer.resolve(cachedFileUrl);
24 | }, defer.reject);
25 | }, defer.reject, defer.notify);
26 | });
27 | return defer.promise;
28 | });
29 | };
30 | });
31 |
--------------------------------------------------------------------------------
/config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | `
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | ionic-webpack
52 |
53 | An Ionic Framework and Cordova project.
54 |
55 |
56 | Ionic Framework Team
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Ionic Webpack starter app
2 |
3 | What's included:
4 |
5 | * __jade__ as templating language (or use html, if don't care)
6 | * __sass__ for style management (with ready-to-go Ionic styles override)
7 | * __js-data__ for data management (let's give it a try instead of Restangular, which is great too)
8 | * __imgcache.js__ and wrapper service to cache loaded images (Google Chrome or Cordova only)
9 | * __environment management__ (check env app/env dir)
10 | * __font preloading__
11 |
12 | Plugins you will need to run app on device:
13 |
14 | * com.ionic.keyboard
15 | * org.apache.cordova.console
16 | * org.apache.cordova.device
17 | * org.apache.cordova.file
18 | * org.apache.cordova.file-transfer
19 | * org.apache.cordova.inappbrowser
20 |
21 | To get started run
22 | ```bash
23 | $ npm install
24 | $ ./dev-server
25 | ```
26 |
27 | Will start development server with live reload on localhost:5000
28 |
29 | To build app run
30 | ```bash
31 | gulp webpack:build
32 | ```
33 |
34 | App will be built into www folder, then you can package ionic app.
35 |
36 | ### Environment management
37 | You can choose environment to build using --env key
38 | ```bash
39 | gulp webpack:build --env=production
40 | ```
41 |
42 | Environment other than __development__ will build minified project using ngAnnotate.
43 | Fonts preloading also enables in __non-development__ environments.
44 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ionic-webpack",
3 | "version": "0.0.1",
4 | "description": "Ionic Webpack starter app",
5 | "scripts": {
6 | "install": "./node_modules/.bin/bower install"
7 | },
8 | "devDependencies": {
9 | "bower": "^1.3.12",
10 | "css-loader": "^0.9.0",
11 | "del": "^0.1.3",
12 | "exports-loader": "^0.6.2",
13 | "expose-loader": "^0.6.0",
14 | "extract-text-webpack-plugin": "^0.3.8",
15 | "file-loader": "^0.7.2",
16 | "gulp": "^3.8.8",
17 | "gulp-util": "^3.0.1",
18 | "html-loader": "^0.2.3",
19 | "html-webpack-plugin": "^1.1.0",
20 | "image-webpack-loader": "^1.2.0",
21 | "imagemin": "^3.1.0",
22 | "imports-loader": "^0.6.3",
23 | "jade": "^1.9.2",
24 | "jade-html-loader": "0.0.2",
25 | "json-loader": "^0.5.1",
26 | "loader-utils": "^0.2.6",
27 | "lodash": "^2.4.1",
28 | "ng-annotate-webpack-plugin": "^0.1.2",
29 | "ngtemplate-loader": "^1.3.0",
30 | "open": "0.0.5",
31 | "sass-loader": "^0.5.0",
32 | "style-loader": "^0.8.3",
33 | "url-loader": "^0.5.5",
34 | "webfontloader": "^1.5.14",
35 | "webpack": "^1.4.5",
36 | "webpack-dev-server": "^1.6.5",
37 | "yargs": "^3.4.5"
38 | },
39 | "dependencies": {
40 | "angular-router-exception-handler": "^1.0.1",
41 | "components-webfontloader": "^1.5.2",
42 | "js-data": "^1.5.13",
43 | "js-data-angular": "^2.2.3"
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/app/jqlite_animate_comment_patch.js:
--------------------------------------------------------------------------------
1 | var _ = require('lodash');
2 | module.exports = patchJQLite;
3 |
4 | function patchJQLite (ngElement){
5 | function after (element, newElement) {
6 | var index = element, parent = element.parentNode;
7 | if(!parent) return;
8 | newElement = new ngElement(newElement);
9 |
10 | for (var i = 0, ii = newElement.length; i < ii; i++) {
11 | var node = newElement[i];
12 | parent.insertBefore(node, index.nextSibling);
13 | index = node;
14 | }
15 | }
16 |
17 | function chain(fn, name) {
18 | /**
19 | * chaining functions
20 | */
21 | ngElement.prototype[name] = function(arg1, arg2, arg3) {
22 | var value;
23 |
24 | for (var i = 0, ii = this.length; i < ii; i++) {
25 | if (_.isUndefined(value)) {
26 | value = fn(this[i], arg1, arg2, arg3);
27 | if (!_.isUndefined(value)) {
28 | // any function which returns a value needs to be wrapped
29 | value = ngElement(value);
30 | }
31 | } else {
32 | jqLiteAddNodes(value, fn(this[i], arg1, arg2, arg3));
33 | }
34 | }
35 | return !_.isUndefined(value) ? value : this;
36 | };
37 | }
38 |
39 | chain(after, 'after');
40 | }
41 |
42 | // AngularJS core code
43 | function jqLiteAddNodes(root, elements) {
44 | // THIS CODE IS VERY HOT. Don't make changes without benchmarking.
45 |
46 | if (elements) {
47 |
48 | // if a Node (the most common case)
49 | if (elements.nodeType) {
50 | root[root.length++] = elements;
51 | } else {
52 | var length = elements.length;
53 |
54 | // if an Array or NodeList and not a Window
55 | if (typeof length === 'number' && elements.window !== elements) {
56 | if (length) {
57 | for (var i = 0; i < length; i++) {
58 | root[root.length++] = elements[i];
59 | }
60 | }
61 | } else {
62 | root[root.length++] = elements;
63 | }
64 | }
65 | }
66 | }
67 |
68 |
--------------------------------------------------------------------------------
/app/components/ui/shrinkable_image_header/directive.js:
--------------------------------------------------------------------------------
1 | var _ = require('lodash');
2 | var directiveTemplateUrl = require('./shrinkable_image_header.html');
3 |
4 | module.exports = ShrinkableImageHeaderProvider;
5 |
6 | /**
7 | * @ngInject
8 | * @constructor
9 | */
10 | function ShrinkableImageHeaderProvider ($parse){
11 | return {
12 | restrict: 'E',
13 | transclude: true,
14 | templateUrl: directiveTemplateUrl,
15 | scope: {
16 | imageUrl: '=imageUrl'
17 | },
18 | replace: true,
19 | link: function ($scope, $element, $attr){
20 | var minHeaderHeight = $attr.minHeight ? $scope.$eval($attr.minHeight) : 0;
21 | var content = angular.element($element.parent()[0].querySelectorAll('ion-content'));
22 |
23 | content.bind('scroll', manageScroll($element,minHeaderHeight))
24 | }
25 | };
26 |
27 | function shrink(header, threshold, minThreshold, amt, dir) {
28 | ionic.requestAnimationFrame(function() {
29 | // Threshold is equal to bar-height
30 |
31 | amt = Math.max(minThreshold, threshold - amt);
32 | amt = Math.min(threshold * 1.3, amt);
33 | amt = amt < 0 ? 0 : amt;
34 | // Re-position the header
35 | header.style[ionic.CSS.TRANSFORM] = 'translate3d(0,-' + (threshold-amt) + 'px, 0)';
36 | });
37 | }
38 |
39 | function manageScroll ($headerImageElement, minThreshold){
40 | var
41 | elem = $headerImageElement[0],
42 | threshold = elem.getBoundingClientRect().height, prev = 0, prevDir = 0, dir = 1, prevShrinkAmt = 0, starty = 0;
43 | return function (e){
44 | var delta;
45 | // Scroll delta
46 | delta = e.detail.scrollTop - prev;
47 | prev = e.detail.scrollTop;
48 |
49 | dir = delta >= 0 ? 1 : -1;
50 | if(dir !== prevDir) starty = e.detail.scrollTop;
51 |
52 | if(dir === 1){
53 | // Calculate expansion amount
54 | //shrinkAmt = prevShrinkAmt - Math.min(threshold, (starty - e.detail.scrollTop));
55 | shrink(elem, threshold, minThreshold, e.detail.scrollTop, dir);
56 | }else{
57 | shrink(elem, threshold, minThreshold, e.detail.scrollTop, dir);
58 | }
59 |
60 | };
61 |
62 | }
63 | }
--------------------------------------------------------------------------------
/app/components/ui/subheader_pane/subheader_pane_content_directive.js:
--------------------------------------------------------------------------------
1 | var _ = require('lodash');
2 | var templateUrl = require('./subheader_pane_content.html');
3 | module.exports = SubheaderPaneContentDirectiveProvider;
4 |
5 |
6 | function SubheaderPaneContentDirectiveProvider (){
7 | return {
8 | restrict: 'E',
9 | templateUrl: templateUrl,
10 | transclude: true,
11 | require: ['^subheaderPane','subheaderPaneContent'],
12 | controller: SubheaderPaneContentController,
13 | link: preLinkFn
14 | };
15 |
16 | function preLinkFn ($scope, iElem, iAttrs, controllers, transcludeFn) {
17 | var subheaderPane = controllers[0];
18 | var paneContent = controllers[1];
19 | subheaderPane.setContent(paneContent);
20 | transcludeFn(function (clone){
21 | var ionContent = angular.element(iElem[0].querySelector('ion-content'));
22 | _.each(iElem[0].attributes, function (value) {
23 | if(value.name == 'class'){
24 | ionContent.addClass(value.value);
25 | }else{
26 | ionContent.attr(value.name, value.value);
27 | }
28 | iElem.removeAttr(value.name);
29 | });
30 | });
31 | }
32 |
33 | function postLinkFn ($scope, iElem, iAttrs, controllers, transcludeFn) {
34 |
35 | }
36 | }
37 |
38 |
39 | function SubheaderPaneContentController ($element){
40 | this.show = _.partial(showHide, true);
41 |
42 | this.hide = _.partial(showHide, false);
43 |
44 | this.showHide = showHide;
45 |
46 | function showHide (show, animate){
47 | var ionContent = $element[0].querySelector('ion-content');
48 | var scroll = angular.element(ionContent).children()[0];
49 | var height;
50 | if(animate) {
51 | ionContent.style[ionic.CSS.TRANSITION] = 'all 0.5s ease-in';
52 | }else{
53 | ionContent.style[ionic.CSS.TRANSITION] = '';
54 | }
55 |
56 | ionContent.style['z-index'] = '10';
57 |
58 | if(show){
59 | ionContent.style[ionic.CSS.TRANSFORM] = 'translate3d(0,0,0)';
60 | }else{
61 | height = ionContent.getBoundingClientRect().height;
62 | ionContent.style[ionic.CSS.TRANSFORM] = 'translate3d(0,-' + height + 'px, 0)';
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/app/components/bootstrap.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * Module dependencies
5 | */
6 | var angular = require('angular');
7 | // set the public path
8 | var scripts = global.document.getElementsByTagName('script');
9 | var src = scripts[scripts.length - 1].getAttribute('src');
10 | global.__webpack_public_path__ = src.substr(0, src.lastIndexOf('/') + 1);
11 |
12 | // Add Angular/Ionic dependencies
13 | require('angular-animate');
14 | require('angular-sanitize');
15 | require('angular-ui-router');
16 | require('ionic/js/ionic');
17 | require('ionic/js/ionic-angular');
18 | require('components-webfontloader');
19 |
20 | var libsModule = module.exports = angular.module('common.libs', [
21 | 'ionic'
22 | ]);
23 |
24 | libsModule.ionicBootstrap = function (module, window, options) {
25 | if (!window || !window.document) {
26 | throw new Error('window and document objects required.');
27 | }
28 |
29 | options = options || {};
30 |
31 | function onDeviceReady () {
32 | // bootstrap angular app
33 | loadFonts(function (){
34 | angular.element(window.document).ready(function () {
35 | angular.bootstrap(window.document, [
36 | module.name
37 | ]);
38 | });
39 | });
40 | // remove document deviceready listener
41 | window.document.removeEventListener('deviceready', onDeviceReady, false);
42 | }
43 |
44 | function onWindowLoad () {
45 | if (!(!window.cordova && !window.PhoneGap && !window.phonegap)) {
46 | // when on device add document deviceready listener
47 | window.document.addEventListener('deviceready', onDeviceReady, false);
48 |
49 | } else {
50 | // when on browser trigger onDeviceReady
51 | onDeviceReady();
52 | }
53 |
54 | // remove window load listener
55 | window.removeEventListener('load', onWindowLoad, false);
56 | }
57 |
58 | function loadFonts (cb){
59 | if((NODE_ENV == 'development') || !options.fonts) return cb();
60 | window.WebFont.load({
61 | custom: {
62 | families: options.fonts,
63 | testStrings: options.fontsTestStrings
64 | },
65 | active: cb
66 | });
67 | }
68 |
69 | // add window load listener
70 | window.addEventListener('load', onWindowLoad, false);
71 | };
72 |
--------------------------------------------------------------------------------
/app/components/ui/static_map/index.js:
--------------------------------------------------------------------------------
1 | STATIC_API_ENDPOINT = 'http://maps.googleapis.com/maps/api/staticmap';
2 | var _ = require('lodash');
3 | var StaticMap = angular.module('app.ui.staticMap', [
4 | require('../../utils/cached_image_loader')
5 | ]);
6 | var templateUrl = require('./static_map.html');
7 |
8 | module.exports = StaticMap.name;
9 |
10 | require('./static_map.scss');
11 |
12 | StaticMap.directive('staticGoogleMap', StaticGoogleMapDirectiveProvider);
13 |
14 | function StaticGoogleMapDirectiveProvider ($timeout, CachedImageLoader){
15 | return {
16 | restrict: 'E',
17 | scope: {
18 | markers: '&markers',
19 | center: '¢er',
20 | zoom: '&zoom'
21 | },
22 | templateUrl: templateUrl,
23 | replace: true,
24 | transclude: true,
25 | link: linkFn
26 | };
27 |
28 | function linkFn ($scope, iElem, iAttrs){
29 |
30 | var timerId = $timeout(setMapLoading, 100);
31 | var clientRect = iElem[0].getBoundingClientRect();
32 | var markers = $scope.markers();
33 | var center = $scope.center();
34 | var zoom = $scope.zoom();
35 |
36 | if(!(markers || center)){
37 | throw 'Error initializing static Google Map - you need to provide either markers or center';
38 | }
39 |
40 | CachedImageLoader(STATIC_API_ENDPOINT + '?' + buildParams())
41 | .then(function (imageSrc){
42 | $timeout.cancel(timerId);
43 | $scope.mapImageUrl = imageSrc;
44 | $timeout(function(){
45 | $scope.loaded = true;
46 | },100);
47 | });
48 |
49 | function setMapLoading (){
50 | $scope.loading = true;
51 | }
52 |
53 | function buildParams (){
54 | var paramStr = 'size='+clientRect.width.toFixed(0)+'x'+clientRect.height.toFixed(0);
55 | if(markers){
56 | paramStr += '&markers=' + _.map(markers, function (marker) {
57 | return _.map(marker, function (v, k){
58 | if(k == 'location'){
59 | return locationParam(v);
60 | }
61 | return k+':'+v;
62 | }).join('|');
63 | }).join('&markers=');
64 | }else{
65 | paramStr += '¢er='+locationParam(center);
66 | }
67 |
68 | if(zoom) paramStr += '&zoom='+zoom;
69 |
70 | return paramStr;
71 | }
72 |
73 | function locationParam (location){
74 | if(_.isArray(location)){
75 | return '' + location[0] + ',' + location[1];
76 | }
77 | return location.lat + ',' + location.lng;
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/app/components/ui/subheader_pane/subheader_pane_directive.js:
--------------------------------------------------------------------------------
1 | var templateUrl = require('./subheader_pane.html');
2 |
3 | module.exports = SubheaderPaneDirectiveProvider;
4 |
5 | function SubheaderPaneDirectiveProvider (){
6 | return {
7 | restrict: 'E',
8 | templateUrl: templateUrl,
9 | replace: true,
10 | transclude: true,
11 | controller: SubheaderPaneController,
12 | priority: 999999,
13 | compile: compile
14 | };
15 |
16 | function compile (){
17 | return {
18 | post: linkFn
19 | }
20 | }
21 |
22 | function linkFn ($scope, iElem, iAttrs, ctrl, transcludeFn){
23 | var sliderPane = angular.element(iElem[0].querySelector('subheader-pane-content'));
24 | sliderPane.detach();
25 | iElem.parent().prepend(sliderPane);
26 | $scope.$$postDigest(function (){
27 | ctrl.init();
28 | });
29 | }
30 | }
31 |
32 | function SubheaderPaneController ($scope, $element, $attrs){
33 | var content, elem = $element[0];
34 | this.show = _.partial(showHide, true);
35 |
36 | this.hide = _.partial(showHide, false);
37 |
38 | this.showHide = showHide;
39 |
40 | function showHide (show, animate){
41 | var height;
42 |
43 | animate = _.isUndefined(animate) ? true : animate;
44 |
45 | //
46 | //_.each($element.children(), function (children){
47 | // if(animate) {
48 | // children.style[ionic.CSS.TRANSITION] = 'all 0.5s ease-in';
49 | // }else{
50 | // children.style[ionic.CSS.TRANSITION] = '';
51 | // }
52 | //});
53 | //
54 | //if(animate) {
55 | // elem.style[ionic.CSS.TRANSITION] = 'all 0.5s ease-in';
56 | //}else{
57 | // elem.style[ionic.CSS.TRANSITION] = '';
58 | //}
59 | //
60 | //if(show){
61 | // elem.style[ionic.CSS.TRANSFORM] = 'translate3d(0,0,0)';
62 | // _.each($element.children(), function (children){
63 | // children.style['opacity'] = '1';
64 | // });
65 | //}else{
66 | // _.each($element.children(), function (children){
67 | // children.style['opacity'] = '0';
68 | // });
69 | // height = elem.getBoundingClientRect().height;
70 | // elem.style[ionic.CSS.TRANSFORM] = 'translate3d(0,-' + height + 'px, 0)';
71 | //}
72 |
73 | content.showHide(show, animate);
74 | if($attrs.onPaneToggle) $scope.$eval($attrs.onPaneToggle, {$visible: show});
75 | }
76 |
77 | this.init = function (){
78 | content && content.hide();
79 | };
80 |
81 | this.setContent = function (_content){
82 | content = _content;
83 | };
84 | }
85 |
86 |
87 |
--------------------------------------------------------------------------------
/hooks/after_prepare/010_add_platform_class.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | // Add Platform Class
4 | // v1.0
5 | // Automatically adds the platform class to the body tag
6 | // after the `prepare` command. By placing the platform CSS classes
7 | // directly in the HTML built for the platform, it speeds up
8 | // rendering the correct layout/style for the specific platform
9 | // instead of waiting for the JS to figure out the correct classes.
10 |
11 | var fs = require('fs');
12 | var path = require('path');
13 |
14 | var rootdir = process.argv[2];
15 |
16 | function addPlatformBodyTag(indexPath, platform) {
17 | // add the platform class to the body tag
18 | try {
19 | var platformClass = 'platform-' + platform;
20 | var cordovaClass = 'platform-cordova platform-webview';
21 |
22 | var html = fs.readFileSync(indexPath, 'utf8');
23 |
24 | var bodyTag = findBodyTag(html);
25 | if(!bodyTag) return; // no opening body tag, something's wrong
26 |
27 | if(bodyTag.indexOf(platformClass) > -1) return; // already added
28 |
29 | var newBodyTag = bodyTag;
30 |
31 | var classAttr = findClassAttr(bodyTag);
32 | if(classAttr) {
33 | // body tag has existing class attribute, add the classname
34 | var endingQuote = classAttr.substring(classAttr.length-1);
35 | var newClassAttr = classAttr.substring(0, classAttr.length-1);
36 | newClassAttr += ' ' + platformClass + ' ' + cordovaClass + endingQuote;
37 | newBodyTag = bodyTag.replace(classAttr, newClassAttr);
38 |
39 | } else {
40 | // add class attribute to the body tag
41 | newBodyTag = bodyTag.replace('>', ' class="' + platformClass + ' ' + cordovaClass + '">');
42 | }
43 |
44 | html = html.replace(bodyTag, newBodyTag);
45 |
46 | fs.writeFileSync(indexPath, html, 'utf8');
47 |
48 | process.stdout.write('add to body class: ' + platformClass + '\n');
49 | } catch(e) {
50 | process.stdout.write(e);
51 | }
52 | }
53 |
54 | function findBodyTag(html) {
55 | // get the body tag
56 | try{
57 | return html.match(/])(.*?)>/gi)[0];
58 | }catch(e){}
59 | }
60 |
61 | function findClassAttr(bodyTag) {
62 | // get the body tag's class attribute
63 | try{
64 | return bodyTag.match(/ class=["|'](.*?)["|']/gi)[0];
65 | }catch(e){}
66 | }
67 |
68 | if (rootdir) {
69 |
70 | // go through each of the platform directories that have been prepared
71 | var platforms = (process.env.CORDOVA_PLATFORMS ? process.env.CORDOVA_PLATFORMS.split(',') : []);
72 |
73 | for(var x=0; x
21 | # Cordova Hooks
22 |
23 | This directory may contain scripts used to customize cordova commands. This
24 | directory used to exist at `.cordova/hooks`, but has now been moved to the
25 | project root. Any scripts you add to these directories will be executed before
26 | and after the commands corresponding to the directory name. Useful for
27 | integrating your own build systems or integrating with version control systems.
28 |
29 | __Remember__: Make your scripts executable.
30 |
31 | ## Hook Directories
32 | The following subdirectories will be used for hooks:
33 |
34 | after_build/
35 | after_compile/
36 | after_docs/
37 | after_emulate/
38 | after_platform_add/
39 | after_platform_rm/
40 | after_platform_ls/
41 | after_plugin_add/
42 | after_plugin_ls/
43 | after_plugin_rm/
44 | after_plugin_search/
45 | after_prepare/
46 | after_run/
47 | after_serve/
48 | before_build/
49 | before_compile/
50 | before_docs/
51 | before_emulate/
52 | before_platform_add/
53 | before_platform_rm/
54 | before_platform_ls/
55 | before_plugin_add/
56 | before_plugin_ls/
57 | before_plugin_rm/
58 | before_plugin_search/
59 | before_prepare/
60 | before_run/
61 | before_serve/
62 | pre_package/ <-- Windows 8 and Windows Phone only.
63 |
64 | ## Script Interface
65 |
66 | All scripts are run from the project's root directory and have the root directory passes as the first argument. All other options are passed to the script using environment variables:
67 |
68 | * CORDOVA_VERSION - The version of the Cordova-CLI.
69 | * CORDOVA_PLATFORMS - Comma separated list of platforms that the command applies to (e.g.: android, ios).
70 | * CORDOVA_PLUGINS - Comma separated list of plugin IDs that the command applies to (e.g.: org.apache.cordova.file, org.apache.cordova.file-transfer)
71 | * CORDOVA_HOOK - Path to the hook that is being executed.
72 | * CORDOVA_CMDLINE - The exact command-line arguments passed to cordova (e.g.: cordova run ios --emulate)
73 |
74 | If a script returns a non-zero exit code, then the parent cordova command will be aborted.
75 |
76 |
77 | ## Writing hooks
78 |
79 | We highly recommend writting your hooks using Node.js so that they are
80 | cross-platform. Some good examples are shown here:
81 |
82 | [http://devgirl.org/2013/11/12/three-hooks-your-cordovaphonegap-project-needs/](http://devgirl.org/2013/11/12/three-hooks-your-cordovaphonegap-project-needs/)
83 |
84 |
--------------------------------------------------------------------------------
/app/components/ui/fake_tabs/index.js:
--------------------------------------------------------------------------------
1 | var FakeTabs = angular.module('app.ui.fakeTabs', []);
2 | var tabsTemplateUrl = require('./fake_tabs.html');
3 | var tabTemplateUrl = require('./fake_tab.html');
4 |
5 | module.exports = FakeTabs.name;
6 |
7 | FakeTabs.directive('ionFakeTabs', FakeTabsProvider);
8 | FakeTabs.directive('ionFakeTab', FakeTabProvider);
9 | /**
10 | * @ngInject
11 | * @constructor
12 | */
13 | function FakeTabsProvider (){
14 | return {
15 | restrict: 'E',
16 | controller: FakeTabsController,
17 | templateUrl: tabsTemplateUrl,
18 | require: 'ionFakeTabs',
19 | transclude: true,
20 | replace: true,
21 | compile: function (tElem, tAttrs){
22 | return {
23 | pre: function ($scope, iElem, iAttrs, fakeTabsCtrl){
24 | $scope.tabs = fakeTabsCtrl;
25 | if(ionic.Platform.isAndroid()){
26 | iElem.children().addClass('tabs-top tabs-striped');
27 | }
28 | },
29 | post: function ($scope, iElem, iAttrs, fakeTabsCtrl){
30 | var navView = angular.element(iElem[0].querySelectorAll('ion-nav-view'));
31 | iElem.append(navView.detach());
32 | }
33 | }
34 | }
35 | };
36 | }
37 |
38 | /**
39 | * @ngInject
40 | * @constructor
41 | */
42 | function FakeTabProvider ($state, $rootScope, $ionicHistory, $ionicViewSwitcher){
43 | return {
44 | restrict: 'E',
45 | transclude: true,
46 | replace: true,
47 | templateUrl: tabTemplateUrl,
48 | scope: true,
49 | compile: function (tElem, tAttrs){
50 | return {
51 | post: function ($scope, iElem, iAttrs){
52 | var cancelListener = $rootScope.$on('$stateChangeSuccess', checkActiveState);
53 |
54 | $scope.active = false;
55 | $scope.hasIcon = !!iAttrs.icon;
56 | $scope.iconClasses = $scope.hasIcon ? iAttrs.icon : null;
57 | $scope.generateHref = generateHref;
58 | $scope.prepareViewSwitch = prepareViewSwitch;
59 |
60 | $scope.$on('$destroy', cancelListener);
61 |
62 | checkActiveState();
63 |
64 | function checkActiveState (){
65 | $scope.active = $state.current.name == iAttrs.sref;
66 | }
67 |
68 | function generateHref (){
69 | return $state.href(iAttrs.sref, iAttrs.srefParams ? $scope.$eval(iAttrs.srefParams) : null);
70 | }
71 |
72 | function prepareViewSwitch (){
73 | if(iAttrs.root){
74 | $ionicHistory.nextViewOptions({
75 | historyRoot: true
76 | });
77 | }
78 | $ionicViewSwitcher.nextDirection(iAttrs.direction || 'forward');
79 | }
80 | }
81 | };
82 | }
83 | };
84 | }
85 |
86 | /**
87 | * @ngInject
88 | * @param $scope
89 | * @param $attrs
90 | * @constructor
91 | */
92 | function FakeTabsController ($scope, $attrs){
93 | var platformClasses = [];
94 | var colorClasses = [];
95 | var contentClasses = [];
96 |
97 | if($attrs.color) colorClasses.push('tabs-color-'+$attrs.color);
98 | if($attrs.background) colorClasses.push('tabs-background-'+$attrs.background);
99 |
100 | if(ionic.Platform.isAndroid()){
101 | $scope.$hasTabsTop = true;
102 | }else{
103 | $scope.$hasTabs = true;
104 | }
105 |
106 | this.classes = [].concat(platformClasses, colorClasses);
107 |
108 | this.getViewClasses = function (){
109 | return contentClasses;
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | var gulp = require("gulp");
2 | var gutil = require('gulp-util');
3 | var webpack = require("webpack");
4 | var ngAnnotateWebpackPlugin = require("ng-annotate-webpack-plugin");
5 | var WebpackDevServer = require("webpack-dev-server");
6 | var webpackConfig = require("./webpack.config.js");
7 | var argv = require('yargs').argv;
8 |
9 | argv.env = argv.env || 'development';
10 |
11 | var src = './src',
12 | dest = './dist',
13 | webpackOptions = {
14 | debug: true,
15 | devtool: '#source-map',
16 | watchDelay: 200
17 | };
18 |
19 | // The development server (the recommended option for development)
20 | gulp.task("default", ["webpack-dev-server"]);
21 |
22 | // Build and watch cycle (another option for development)
23 | // Advantage: No server required, can run app from filesystem
24 | // Disadvantage: Requests are not blocked until bundle is available,
25 | // can serve an old app on refresh
26 | gulp.task("build-dev", ["webpack:build-dev"], function() {
27 | gulp.watch(["src/**/*"], ["webpack:build-dev"]);
28 | });
29 |
30 | // Production build
31 | gulp.task("build", ["webpack:build"]);
32 |
33 | gulp.task("webpack:build", function(callback) {
34 | // modify some webpack config options
35 | var myConfig = Object.create(webpackConfig);
36 |
37 | if(argv.env != 'development'){
38 | myConfig.plugins = myConfig.plugins.concat(
39 | new ngAnnotateWebpackPlugin({
40 | add: true
41 | }),
42 | new webpack.optimize.DedupePlugin(),
43 | new webpack.optimize.UglifyJsPlugin({
44 | output: {comments: false}
45 | })
46 | );
47 | }
48 |
49 | // run webpack
50 | webpack(myConfig, function(err, stats) {
51 | if(err) throw new gutil.PluginError("webpack:build", err);
52 | gutil.log("[webpack:build]", stats.toString({
53 | colors: true
54 | }));
55 | callback();
56 | });
57 | });
58 |
59 | // modify some webpack config options
60 | var myDevConfig = Object.create(webpackConfig);
61 | myDevConfig.devtool = "sourcemap";
62 | myDevConfig.debug = true;
63 |
64 | // create a single instance of the compiler to allow caching
65 | var devCompiler = webpack(myDevConfig);
66 |
67 | gulp.task("webpack:build-dev", function(callback) {
68 | // run webpack
69 | devCompiler.run(function(err, stats) {
70 | if(err) throw new gutil.PluginError("webpack:build-dev", err);
71 | gutil.log("[webpack:build-dev]", stats.toString({
72 | colors: true
73 | }));
74 | callback();
75 | });
76 | });
77 |
78 | gulp.task("webpack-dev-server", function(callback) {
79 | // modify some webpack config options
80 | var myConfig = Object.create(webpackConfig);
81 | myConfig.devtool = "eval";
82 | myConfig.debug = true;
83 |
84 | // Start a webpack-dev-server
85 | new WebpackDevServer(webpack(myConfig), {
86 | publicPath: "/www",
87 | inline: true,
88 | hot: true,
89 | stats: {
90 | colors: true
91 | }
92 | }).listen(5000, "localhost", function(err) {
93 | if(err) throw new gutil.PluginError("webpack-dev-server", err);
94 | gutil.log("[webpack-dev-server]", "http://localhost:5000/webpack-dev-server/index.html");
95 | });
96 | });
97 |
98 | gulp.task("webpack-test-server", function(callback) {
99 | // modify some webpack config options
100 | var myConfig = Object.create(webpackConfig);
101 | myConfig.debug = false;
102 |
103 | // Start a webpack-dev-server
104 | new WebpackDevServer(webpack(myConfig), {
105 | publicPath: "/",
106 | inline: true,
107 | stats: {
108 | colors: true
109 | }
110 | }).listen(5000, "localhost", function(err) {
111 | if(err) throw new gutil.PluginError("webpack-dev-server", err);
112 | gutil.log("[webpack-dev-server]", "http://localhost:5000/webpack-dev-server/index.html");
113 | });
114 | });
115 |
116 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | var _ = require("lodash");
2 | var path = require("path");
3 | var webpack = require("webpack");
4 | var HtmlWebpackPlugin = require('html-webpack-plugin');
5 | var ExtractTextPlugin = require("extract-text-webpack-plugin");
6 | var argv = require('yargs').argv;
7 | var cssLoaders, plugins;
8 | var appRoot = path.resolve(__dirname, "./app");
9 |
10 | argv.env = argv.env || 'development';
11 |
12 |
13 | if(argv.env != 'development'){
14 | cssLoaders = [
15 | { test: /\.css$/, loader: ExtractTextPlugin.extract("style-loader", "css-loader?root="+appRoot) },
16 | { test: /\.less$/, loader: ExtractTextPlugin.extract("style-loader", "css-loader?root="+appRoot+"!less-loader") },
17 | { test: /\.scss$/, loader: ExtractTextPlugin.extract("style-loader","css-loader?root="+appRoot+"!sass") }
18 | ];
19 | plugins = [
20 | new ExtractTextPlugin("[name].css")
21 | ];
22 |
23 |
24 | }else{
25 | cssLoaders = [
26 | { test: /\.css$/, loader: "style-loader!css-loader?root="+appRoot },
27 | { test: /\.less$/, loader: "style-loader!css-loader?root="+appRoot+"!less-loader" },
28 | { test: /\.scss$/, loader: "style-loader!css-loader?root="+appRoot+"!sass" }
29 | ];
30 | plugins = [];
31 | }
32 |
33 | module.exports = {
34 | cache: true,
35 | debug: true,
36 | devTool: 'eval',
37 | entry: {
38 | vendor: ['angular', 'angular-ui-router', 'lodash', 'angular-animate', 'angular-cache', 'angular-sanitize', 'js-data', 'js-data-angular'],
39 | app: ['./app/index']
40 | },
41 | output: {
42 | path: path.join(__dirname, "www"),
43 | filename: "[name].bundle.js",
44 | chunkFilename: "[id].bundle.js"
45 | },
46 | module: {
47 | loaders: cssLoaders.concat([
48 | { test: /\.(jpe?g|png|gif)$/i, loader: 'image?bypassOnDebug&optimizationLevel=7&interlaced=false' },
49 | {
50 | test : /\.json$/,
51 | loader : 'json'
52 | },
53 | { test: /\.html$/,
54 | loader: "ngtemplate?relativeTo=" + (path.resolve(__dirname, './app')) + "/&module=templates!html?root=app"},
55 | { test: /\.jade$/,
56 | loader: "ngtemplate?relativeTo=" + (path.resolve(__dirname, './app')) + "/&module=templates!html!jade-html"},
57 | { test: /\.woff($|\?)/, loader: 'url-loader?prefix=font/&limit=5000&mimetype=application/font-woff' },
58 | { test: /\.woff2($|\?)/, loader: 'url-loader?prefix=font/&limit=5000&mimetype=application/font-woff' },
59 | { test: /\.ttf($|\?)/, loader: "file-loader?prefix=font/" },
60 | { test: /\.eot($|\?)/, loader: "file-loader?prefix=font/" },
61 | { test: /\.svg($|\?)/, loader: "file-loader?prefix=font/" },
62 | {
63 | test : /[\/]angular\.js$/,
64 | loader : 'exports?angular'
65 | }, {
66 | test : /[\/]ionic\.js$/,
67 | loader : 'exports?ionic'
68 | }
69 | ]),
70 | noParse: [
71 | /bower_components/
72 | ]
73 | },
74 | resolve: {
75 | root: [
76 | path.join(__dirname, 'app'),
77 | path.join(__dirname, 'bower_components'),
78 | path.join(__dirname, 'node_modules')
79 | ],
80 | moduleDirectories: [
81 | 'bower_components',
82 | 'node_modules'
83 | ],
84 | alias: {
85 | app: [path.join(__dirname, 'app')]
86 | }
87 | },
88 | externals: {
89 | 'js-data-schema': 'undefined'
90 | },
91 | plugins: plugins.concat([
92 | new webpack.ProvidePlugin({
93 | _: "lodash"
94 | }),
95 | new webpack.ResolverPlugin(
96 | new webpack.ResolverPlugin.DirectoryDescriptionFilePlugin(
97 | 'bower.json', ['main'])
98 | ),
99 | new webpack.DefinePlugin({
100 | NODE_ENV: JSON.stringify(argv.env || 'development')
101 | }),
102 | new webpack.optimize.CommonsChunkPlugin({
103 | name: 'vendor',
104 | minChunks: Infinity
105 | }),
106 | new HtmlWebpackPlugin({
107 | pkg : require('./package.json'),
108 | template : 'app/index.html',
109 | env : argv.env || 'development'
110 | })
111 | ])
112 | };
113 |
--------------------------------------------------------------------------------
/app/fonts.scss:
--------------------------------------------------------------------------------
1 | /* cyrillic-ext */
2 | @font-face {
3 | font-family: 'Comfortaa';
4 | font-style: normal;
5 | font-weight: 300;
6 | src: local('Comfortaa Light'), local('Comfortaa-Light'), url(./fonts/r_tUZNl0G8xCoOmp_JkSCg7aC6SjiAOpAWOKfJDfVRY.woff2) format('woff2');
7 | unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
8 | }
9 | /* cyrillic */
10 | @font-face {
11 | font-family: 'Comfortaa';
12 | font-style: normal;
13 | font-weight: 300;
14 | src: local('Comfortaa Light'), local('Comfortaa-Light'), url(./fonts/r_tUZNl0G8xCoOmp_JkSChdwxCXfZpKo5kWAx_74bHs.woff2) format('woff2');
15 | unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
16 | }
17 | /* greek */
18 | @font-face {
19 | font-family: 'Comfortaa';
20 | font-style: normal;
21 | font-weight: 300;
22 | src: local('Comfortaa Light'), local('Comfortaa-Light'), url(./fonts/r_tUZNl0G8xCoOmp_JkSCvy1_HTwRwgtl1cPga3Fy3Y.woff2) format('woff2');
23 | unicode-range: U+0370-03FF;
24 | }
25 | /* latin-ext */
26 | @font-face {
27 | font-family: 'Comfortaa';
28 | font-style: normal;
29 | font-weight: 300;
30 | src: local('Comfortaa Light'), local('Comfortaa-Light'), url(./fonts/r_tUZNl0G8xCoOmp_JkSCojoYw3YTyktCCer_ilOlhE.woff2) format('woff2');
31 | unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
32 | }
33 | /* latin */
34 | @font-face {
35 | font-family: 'Comfortaa';
36 | font-style: normal;
37 | font-weight: 300;
38 | src: local('Comfortaa Light'), local('Comfortaa-Light'), url(./fonts/r_tUZNl0G8xCoOmp_JkSChampu5_7CjHW5spxoeN3Vs.woff2) format('woff2');
39 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
40 | }
41 | /* cyrillic-ext */
42 | @font-face {
43 | font-family: 'Comfortaa';
44 | font-style: normal;
45 | font-weight: 400;
46 | src: local('Comfortaa'), local('Comfortaa-Regular'), url(./fonts/Be0CkOtwwI2n86HMhtablYX0hVgzZQUfRDuZrPvH3D8.woff2) format('woff2');
47 | unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
48 | }
49 | /* cyrillic */
50 | @font-face {
51 | font-family: 'Comfortaa';
52 | font-style: normal;
53 | font-weight: 400;
54 | src: local('Comfortaa'), local('Comfortaa-Regular'), url(./fonts/-DackuIFgo7Hfy3rR14C34X0hVgzZQUfRDuZrPvH3D8.woff2) format('woff2');
55 | unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
56 | }
57 | /* greek */
58 | @font-face {
59 | font-family: 'Comfortaa';
60 | font-style: normal;
61 | font-weight: 400;
62 | src: local('Comfortaa'), local('Comfortaa-Regular'), url(./fonts/UgYUhLCkRUocJ8OZnvelZ4X0hVgzZQUfRDuZrPvH3D8.woff2) format('woff2');
63 | unicode-range: U+0370-03FF;
64 | }
65 | /* latin-ext */
66 | @font-face {
67 | font-family: 'Comfortaa';
68 | font-style: normal;
69 | font-weight: 400;
70 | src: local('Comfortaa'), local('Comfortaa-Regular'), url(./fonts/wz1gqe57Mbg11v-OrLlVjoX0hVgzZQUfRDuZrPvH3D8.woff2) format('woff2');
71 | unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
72 | }
73 | /* latin */
74 | @font-face {
75 | font-family: 'Comfortaa';
76 | font-style: normal;
77 | font-weight: 400;
78 | src: local('Comfortaa'), local('Comfortaa-Regular'), url(./fonts/qLBu5CQmSMt1H43OiWJ77ZBw1xU1rKptJj_0jans920.woff2) format('woff2');
79 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
80 | }
81 | /* cyrillic-ext */
82 | @font-face {
83 | font-family: 'Comfortaa';
84 | font-style: normal;
85 | font-weight: 700;
86 | src: local('Comfortaa Bold'), local('Comfortaa-Bold'), url(./fonts/fND5XPYKrF2tQDwwfWZJIw7aC6SjiAOpAWOKfJDfVRY.woff2) format('woff2');
87 | unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
88 | }
89 | /* cyrillic */
90 | @font-face {
91 | font-family: 'Comfortaa';
92 | font-style: normal;
93 | font-weight: 700;
94 | src: local('Comfortaa Bold'), local('Comfortaa-Bold'), url(./fonts/fND5XPYKrF2tQDwwfWZJIxdwxCXfZpKo5kWAx_74bHs.woff2) format('woff2');
95 | unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
96 | }
97 | /* greek */
98 | @font-face {
99 | font-family: 'Comfortaa';
100 | font-style: normal;
101 | font-weight: 700;
102 | src: local('Comfortaa Bold'), local('Comfortaa-Bold'), url(./fonts/fND5XPYKrF2tQDwwfWZJI_y1_HTwRwgtl1cPga3Fy3Y.woff2) format('woff2');
103 | unicode-range: U+0370-03FF;
104 | }
105 | /* latin-ext */
106 | @font-face {
107 | font-family: 'Comfortaa';
108 | font-style: normal;
109 | font-weight: 700;
110 | src: local('Comfortaa Bold'), local('Comfortaa-Bold'), url(./fonts/fND5XPYKrF2tQDwwfWZJI4joYw3YTyktCCer_ilOlhE.woff2) format('woff2');
111 | unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
112 | }
113 | /* latin */
114 | @font-face {
115 | font-family: 'Comfortaa';
116 | font-style: normal;
117 | font-weight: 700;
118 | src: local('Comfortaa Bold'), local('Comfortaa-Bold'), url(./fonts/fND5XPYKrF2tQDwwfWZJIxampu5_7CjHW5spxoeN3Vs.woff2) format('woff2');
119 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
120 | }
--------------------------------------------------------------------------------