Android Address Book with AngularJs and MongoDB ('-' * 47)
A Pen by Daniele Moraschi on CodePen.
Android Address Book with AngularJs and MongoDB ('-' * 47)
A Pen by Daniele Moraschi on CodePen.
| <style> | |
| @import url(http://weloveiconfonts.com/api/?family=entypo); | |
| [class*="entypo-"]:before { | |
| font-family: 'entypo', sans-serif; | |
| } | |
| </style> | |
| <div ng-app="android-addressbook"> | |
| <div ng-controller="AddressBook.Init"> | |
| <div class="row main-app"> | |
| <div ng-view></div> | |
| </div> | |
| </div> | |
| <script type="text/ng-template" id="list.html"> | |
| <ul class="fixed top full bar topbar tabs two"> | |
| <li class="icon active"> | |
| <a href='#/contacts'><span class="entypo-user"></span></a> | |
| </li> | |
| <li class="icon"> | |
| <a href='#/contacts/starred'><span class="entypo-star"></span></a> | |
| </li> | |
| </ul> | |
| <div class="content" id="wrapper"> | |
| <div class="lists" id="scroller"> | |
| <div ng:repeat="group in groups"> | |
| <div class="title fleft full">{{ group.label }}</div> | |
| <ul class="list single-fill"> | |
| <li class="list-item" ng:repeat="contact in group.contacts"> | |
| <a class="item" href='#/contact/view/{{ contact._id.$oid }}'> | |
| <span class="fleft name">{{ contact.firstName + ' ' + contact.lastName }}</span> | |
| <span class="fright image"><img width="60" ng-src="{{ ProfileImage('60x60', contact) }}"/></span> | |
| </a> | |
| </li> | |
| </ul> | |
| </div> | |
| </div> | |
| </div> | |
| <ul class="fixed bottom full bar bottombar"> | |
| <li class="icon icn left"> | |
| <a href='#/contacts/search'><span class="entypo-search"></span></a> | |
| </li> | |
| <li class="icon icn center"> | |
| <a href='#/contact/add'><span class="entypo-user-add"></span></a> | |
| </li> | |
| </ul> | |
| </script> | |
| <script type="text/ng-template" id="starred.html"> | |
| <ul class="fixed top full bar topbar tabs two"> | |
| <li class="icon"> | |
| <a href='#/contacts'><span class="entypo-user"></span></a> | |
| </li> | |
| <li class="icon active"> | |
| <a href='#/contacts/starred'><span class="entypo-star"></span></a> | |
| </li> | |
| </ul> | |
| <div class="content" id="wrapper"> | |
| <div id="scroller" class="fleft"> | |
| <div class="lists full"> | |
| <ul class="list single-fill"> | |
| <li class="list-item half" ng:repeat="contact in starred"> | |
| <a class="item profile-image" href='#/contact/view/{{ contact._id.$oid }}'> | |
| <img width="100%" ng-src="{{ ProfileImage('480x480', contact) }}"/> | |
| <span class="absolute bottom caption"> | |
| <span class="text">{{ contact.firstName + ' ' + contact.lastName }}</span> | |
| <span class="overlay"></span> | |
| </span> | |
| </a> | |
| </li> | |
| </ul> | |
| </div> | |
| <div class="lists"> | |
| <div class="title fleft full">Frequently viewed</div> | |
| <ul class="list single-fill"> | |
| <li class="list-item" ng:repeat="contact in contacts"> | |
| <a class="item" href='#/contact/view/{{ contact._id.$oid }}'> | |
| <span class="fleft name">{{ contact.firstName + ' ' + contact.lastName }}</span> | |
| <span class="fright image"><img width="60" ng-src="{{ ProfileImage('60x60', contact) }}"/></span> | |
| </a> | |
| </li> | |
| </ul> | |
| </div> | |
| </div> | |
| </div> | |
| <ul class="fixed bottom full bar bottombar"> | |
| <li class="icon icn left"> | |
| <a href='#/contacts/search'><span class="entypo-search"></span></a> | |
| </li> | |
| <li class="icon icn center"> | |
| <a href='#/contact/add'><span class="entypo-user-add"></span></a> | |
| </li> | |
| </ul> | |
| </script> | |
| <script type="text/ng-template" id="search.html"> | |
| <ul class="fixed top full bar topbar"> | |
| <li class="icon icn left"> | |
| <a href='javascript:void(0)' ng-click="Back()"><span class="entypo-left-open-big"></span></a> | |
| </li> | |
| <li class="contact-name icn full form"> | |
| <div class="form-item"> | |
| <input placeholder="Find contacts" type="text" id="searchterm" name="searchterm" ng-model="searchterm"/> | |
| <span class="form-item-decorator"></span> | |
| <span class="cancel entypo-cancel-circled" ng-show="searchterm" ng-click="searchterm=''"></span> | |
| </div> | |
| </li> | |
| </ul> | |
| <div class="content no-bottombar" id="wrapper"> | |
| <div class="lists" id="scroller"> | |
| <div ng:repeat="group in groups"> | |
| <div class="title fleft full">{{ group.label }}</div> | |
| <ul class="list single-fill"> | |
| <li class="list-item" ng:repeat="contact in group.contacts | filter:searchterm"> | |
| <a class="item" href='#/contact/view/{{ contact._id.$oid }}'> | |
| <span class="fleft name">{{ contact.firstName + ' ' + contact.lastName }}</span> | |
| <span class="fright image"><img width="60" ng-src="{{ ProfileImage('60x60', contact) }}"/></span> | |
| </a> | |
| </li> | |
| </ul> | |
| </div> | |
| </div> | |
| </div> | |
| </script> | |
| <script type="text/ng-template" id="view.html"> | |
| <ul class="fixed top full bar topbar"> | |
| <li class="icon icn left"> | |
| <a href='javascript:void(0)' ng-click="Back()"><span class="entypo-left-open-big"></span></a> | |
| </li> | |
| <li class="contact-name icn full" ng-bind="FullName()"></li> | |
| <li class="icon icn right sec"> | |
| <a href='javascript:void(0)'><span ng-click="StarUnStar()" ng-class="{'entypo-star': contact.starred, 'entypo-star-empty': !contact.starred}"></span></a> | |
| </li> | |
| <li class="icon icn right" ng-click="_submenu()" ng-class="{'show-submenu': submenu}"> | |
| <a href='javascript:void(0)'><span class="entypo-pencil"></span></a> | |
| <ul class="submenu"> | |
| <li> | |
| <a href='#/contact/edit/{{ contact._id.$oid }}'>edit</a> | |
| </li> | |
| <li> | |
| <a href='javascript:void(0)' ng-click="DeleteContact()">delete</a> | |
| </li> | |
| </ul> | |
| </li> | |
| </ul> | |
| <div class="content no-bottombar" id="wrapper"> | |
| <div class="lists fleft" id="scroller"> | |
| <div class="profile-image" ng-click="_showImage()" ng-class="{open: selected}"> | |
| <img ng-src="{{ ProfileImage('480x480') }}"/> | |
| </div> | |
| <div ng-show="contact.phones.length"> | |
| <div class="title fleft full">Phone</div> | |
| <ul class="list"> | |
| <li class="list-item" ng:repeat="item in contact.phones"> | |
| <a class="item" href="tel:{{ item.value }}"> | |
| <span class="value">{{ item.value }}</span> | |
| <span class="label">{{ item.type }}</span> | |
| </a> | |
| </li> | |
| </ul> | |
| </div> | |
| <div ng-show="contact.emails.length"> | |
| <div class="title fleft full">Email</div> | |
| <ul class="list"> | |
| <li class="list-item" ng:repeat="item in contact.emails"> | |
| <a class="item" target="_black" href="mailto:{{ item.value }}"> | |
| <span class="value">{{ item.value }}</span> | |
| <span class="label">{{ item.type }}</span> | |
| </a> | |
| </li> | |
| </ul> | |
| </div> | |
| <div ng-show="contact.addresses.length"> | |
| <div class="title fleft full">Address</div> | |
| <ul class="list"> | |
| <li class="list-item" ng:repeat="item in contact.addresses"> | |
| <a class="item" target="_black" href="https://maps.google.com/maps?q={{ item.value }}"> | |
| <span class="value">{{ item.value }}</span> | |
| <span class="label">{{ item.type }}</span> | |
| </a> | |
| </li> | |
| </ul> | |
| </div> | |
| <div ng-show="contact.birthday"> | |
| <div class="title fleft full">Birthday</div> | |
| <ul class="list"> | |
| <li class="list-item"> | |
| <span class="item"> | |
| <span class="value">{{ contact.birthday }}</span> | |
| </span> | |
| </li> | |
| </ul> | |
| </div> | |
| <div ng-show="contact.websites.length"> | |
| <div class="title fleft full">Websites</div> | |
| <ul class="list"> | |
| <li class="list-item" ng:repeat="item in contact.websites"> | |
| <a class="item" target="_black" href="{{ item.value }}"> | |
| <span class="value">{{ item.value }}</span> | |
| <span class="label">{{ item.type }}</span> | |
| </a> | |
| </li> | |
| </ul> | |
| </div> | |
| <div ng-show="contact.notes"> | |
| <div class="title fleft full">Notes</div> | |
| <ul class="list"> | |
| <li class="list-item"> | |
| <span class="item"> | |
| <span class="value">{{ contact.notes }}</span> | |
| </span> | |
| </li> | |
| </ul> | |
| </div> | |
| </div> | |
| </div> | |
| </script> | |
| <script type="text/ng-template" id="edit.html"> | |
| <ul class="fixed top full bar topbar"> | |
| <li class="icon icn left"> | |
| <a href='javascript:void(0)' ng-click="SaveContact()"><span ng-class="{'entypo-dot': contactForm.name.$invalid, 'entypo-check': !contactForm.name.$invalid}"></span></a> | |
| </li> | |
| <li class="contact-name icn full" ng-bind="FullName()"></li> | |
| <li class="icon icn right" ng-show="contact._id.$oid"> | |
| <a ng-href="#/contact/view/{{ contact._id.$oid }}"><span class="entypo-cancel"></span></a> | |
| </li> | |
| <li class="icon icn right" ng-show="!contact._id.$oid"> | |
| <a href='javascript:void(0)' ng-click="Back()"><span class="entypo-cancel"></span></a> | |
| </li> | |
| </ul> | |
| <div class="content no-bottombar" id="wrapper"> | |
| <div class="lists fleft" id="scroller"> | |
| <form class="form" name="contactForm"> | |
| <div class="title fleft full">Name</div> | |
| <ul class="list"> | |
| <li class="list-item"> | |
| <div class="item form-item"> | |
| <input type="text" name="name" maxlength="25" ng-model="contact.firstName" required /> | |
| <span class="form-item-decorator"></span> | |
| </div> | |
| </li> | |
| <li class="list-item"> | |
| <div class="item form-item"> | |
| <input type="text" maxlength="25" ng-model="contact.lastName"/> | |
| <span class="form-item-decorator"></span> | |
| </div> | |
| </li> | |
| </ul> | |
| <div class="title fleft full">Picture URL</div> | |
| <ul class="list"> | |
| <li class="list-item"> | |
| <div class="item form-item field-left img"> | |
| <input type="text" ng-model="contact.picture"/> | |
| <span class="form-item-decorator"></span> | |
| </div> | |
| <div class="item form-item field-right img"> | |
| <img width="60" ng-src="{{ ProfileImage('60x60') }}"/> | |
| </div> | |
| </li> | |
| </ul> | |
| <div class="title fleft full">Phone</div> | |
| <ul class="list"> | |
| <li class="list-item" ng:repeat="item in contact.phones"> | |
| <div class="item form-item field-left"> | |
| <input type="text" ng-model="item.value"/> | |
| <span class="form-item-decorator"></span> | |
| </div> | |
| <div class="item form-item field-right"> | |
| <input type="text" ng-model="item.type"/> | |
| <span class="form-item-decorator"></span> | |
| </div> | |
| <div class="item form-item field-right-right action"> | |
| <button class="delete" ng-click="DiscardField('phones', $index)"><span class="entypo-cancel"></span></button> | |
| </div> | |
| </li> | |
| <li class="list-item action"> | |
| <button class="save" ng-click="AddField('phones')">Add new</button> | |
| </li> | |
| </ul> | |
| <div class="title fleft full">Email</div> | |
| <ul class="list"> | |
| <li class="list-item" ng:repeat="item in contact.emails"> | |
| <div class="item form-item field-left"> | |
| <input type="text" ng-model="item.value"/> | |
| <span class="form-item-decorator"></span> | |
| </div> | |
| <div class="item form-item field-right"> | |
| <input type="text" ng-model="item.type"/> | |
| <span class="form-item-decorator"></span> | |
| </div> | |
| <div class="item form-item field-right-right action"> | |
| <button class="delete" ng-click="DiscardField('emails', $index)"><span class="entypo-cancel"></span></button> | |
| </div> | |
| </li> | |
| <li class="list-item action"> | |
| <button class="save" ng-click="AddField('emails')">Add new</button> | |
| </li> | |
| </ul> | |
| <div class="title fleft full">Address</div> | |
| <ul class="list"> | |
| <li class="list-item" ng:repeat="item in contact.addresses"> | |
| <div class="item form-item field-left"> | |
| <input type="text" ng-model="item.value"/> | |
| <span class="form-item-decorator"></span> | |
| </div> | |
| <div class="item form-item field-right"> | |
| <input type="text" ng-model="item.type"/> | |
| <span class="form-item-decorator"></span> | |
| </div> | |
| <div class="item form-item field-right-right action"> | |
| <button class="delete" ng-click="DiscardField('addresses', $index)"><span class="entypo-cancel"></span></button> | |
| </div> | |
| </li> | |
| <li class="list-item action"> | |
| <button class="save" ng-click="AddField('addresses')">Add new</button> | |
| </li> | |
| </ul> | |
| <div class="title fleft full">Birthday</div> | |
| <ul class="list"> | |
| <li class="list-item"> | |
| <div class="item form-item"> | |
| <input type="date" ng-model="contact.birthday"/> | |
| <span class="form-item-decorator"></span> | |
| </div> | |
| </li> | |
| </ul> | |
| <div class="title fleft full">Websites</div> | |
| <ul class="list"> | |
| <li class="list-item" ng:repeat="item in contact.websites"> | |
| <div class="item form-item field-left"> | |
| <input type="url" ng-model="item.value"/> | |
| <span class="form-item-decorator"></span> | |
| </div> | |
| <div class="item form-item field-right"> | |
| <input type="text" ng-model="item.type"/> | |
| <span class="form-item-decorator"></span> | |
| </div> | |
| <div class="item form-item field-right-right action"> | |
| <button class="delete" ng-click="DiscardField('websites', $index)"><span class="entypo-cancel"></span></button> | |
| </div> | |
| </li> | |
| <li class="list-item action"> | |
| <button class="save" ng-click="AddField('websites')">Add new</button> | |
| </li> | |
| </ul> | |
| <div class="title fleft full">Notes</div> | |
| <ul class="list"> | |
| <li class="list-item"> | |
| <div class="item form-item"> | |
| <textarea ng-model="contact.notes"></textarea> | |
| <span class="form-item-decorator"></span> | |
| </div> | |
| </li> | |
| </ul> | |
| </form> | |
| </div> | |
| </div> | |
| </script> | |
| </div> |
| 'use strict'; | |
| /* | |
| Android Address Book replica with AngularJs | |
| =========================================== | |
| GitHub project: https://github.com/danielemoraschi/android-addressbook | |
| Touch scrolling by iScroll: http://cubiq.org/iscroll-4 | |
| Fake contacts list by: http://www.generatedata.com/ | |
| DB reset every 2h | |
| Best in Mobile / Chrome / Safari | |
| Released under the MIT License: | |
| http://www.opensource.org/licenses/mit-license.php | |
| */ | |
| var AddressBook = (function() { | |
| var iscroll, current_route, | |
| _init = function($scope) { | |
| iscroll = null; | |
| current_route = '/contacts'; | |
| }, | |
| _iScroll = function() { | |
| iscroll && iscroll.destroy(); | |
| iscroll = new iScroll('wrapper', { hScroll: false }); | |
| setTimeout(function() { | |
| iscroll.refresh(); | |
| }, 0); | |
| }, | |
| _detail_ctrl = function($scope, $location, $routeParams, Utils, Contacts) { | |
| var self = this; | |
| $scope.selected = false; | |
| $scope.submenu = false; | |
| $scope.contact = { | |
| starred: false, | |
| firstName: "", | |
| lastName: "", | |
| birthday: "", | |
| picture: "", | |
| phones: [], | |
| emails: [], | |
| addresses: [], | |
| websites: [], | |
| notes: "" | |
| }; | |
| $scope._showImage = function() { | |
| $scope.selected = !$scope.selected; | |
| } | |
| $scope._submenu = function() { | |
| $scope.submenu = !$scope.submenu; | |
| } | |
| $scope.Back = function() { | |
| $location.path(current_route); | |
| } | |
| $scope.ProfileImage = function(dim) { | |
| return ($scope.contact && $scope.contact.picture) || "https://raw.github.com/danielemoraschi/android-addressbook/master/imgs/ic_contact_picture_"+dim+".png"; | |
| } | |
| $scope.FullName = function(dim) { | |
| return ($scope.contact.firstName && $scope.contact.firstName.trim()) | |
| ? $scope.contact.firstName + ' ' + $scope.contact.lastName | |
| : ($scope.contact._id ? 'No name' : 'New contact'); | |
| } | |
| $scope.StarUnStar = function () { | |
| $scope.contact.starred = !$scope.contact.starred; | |
| $scope.contact.update(); | |
| } | |
| $scope.AddField = function(type) { | |
| $scope.contact[type] || ($scope.contact[type] = []); | |
| $scope.contact[type].push({ | |
| type: '', | |
| value: '' | |
| }); | |
| } | |
| $scope.DiscardField = function(type, index) { | |
| if($scope.contact[type] && $scope.contact[type][index]) { | |
| $scope.contact[type].splice(index,1); | |
| } | |
| } | |
| $scope.SaveContact = function () { | |
| if($scope.contact.firstName && $scope.contact.firstName.trim()) { | |
| var arrays = {'phones': [], 'emails': [], 'addresses': []}; | |
| angular.forEach(arrays, function(v, k) { | |
| angular.forEach($scope.contact[k], function(val, key) { | |
| if(val.value.trim()) { | |
| arrays[k].push(val); | |
| } | |
| }); | |
| $scope.contact[k] = arrays[k]; | |
| }); | |
| if($scope.contact._id) { | |
| $scope.contact.update(function() { | |
| $location.path('/contact/view/' + $scope.contact._id.$oid); | |
| }); | |
| } | |
| else { | |
| Contacts.save($scope.contact, function(contact) { | |
| $location.path('/contact/edit/' + contact._id.$oid); | |
| }); | |
| } | |
| } | |
| } | |
| $scope.DeleteContact = function () { | |
| if($scope.contact._id.$oid) { | |
| var c = confirm("Delete this contact?") | |
| if (c==true) { | |
| self.original.delete(function() { | |
| $location.path('/contacts'); | |
| }); | |
| } | |
| } | |
| } | |
| if($routeParams.id) { | |
| Contacts.get({id: $routeParams.id}, function(contact) { | |
| self.original = contact; | |
| if(!self.original.views) { | |
| self.original.views = 0; | |
| } | |
| self.original.views++; | |
| $scope.contact = new Contacts(self.original); | |
| $scope.contact.update(); | |
| _iScroll(); | |
| }); | |
| } else { | |
| _iScroll(); | |
| } | |
| }, | |
| _list_ctrl = function($scope, $location, $routeParams, Utils, Contacts) { | |
| var i, ch, self = this; | |
| $scope.orderProp = 'firstName'; | |
| $scope.groups = {}; | |
| $scope.contacts = {}; | |
| $scope.starred = {}; | |
| $scope.searchterm = ''; | |
| $scope.ProfileImage = function(dim, contact) { | |
| return contact.picture ? contact.picture.replace("480x480", dim) : "https://raw.github.com/danielemoraschi/android-addressbook/master/imgs/ic_contact_picture_"+dim+".png"; | |
| } | |
| $scope.Back = function() { | |
| $location.path(current_route); | |
| } | |
| switch($location.$$url) { | |
| case "/contacts/starred": | |
| current_route = $location.$$url; | |
| $scope.starred = Contacts.query({q: '{"starred":true}'}, function() { | |
| $scope.contacts = Contacts.query({q: '{"views":{"$gt":0}}', l: 10}, function() { | |
| _iScroll(); | |
| }); | |
| }); | |
| break; | |
| case "/contacts/search": | |
| $scope.contacts = Contacts.query(function() { | |
| $scope.groups = [{ | |
| label: 'All contacts', | |
| contacts: $scope.contacts | |
| }]; | |
| _iScroll(); | |
| }); | |
| break; | |
| default: | |
| current_route = $location.$$url; | |
| $scope.contacts = Contacts.query(function() { | |
| Utils.groupify($scope.contacts, $scope.groups); | |
| _iScroll(); | |
| }); | |
| break; | |
| } | |
| }; | |
| return { | |
| Init: _init, | |
| DetailCtrl: _detail_ctrl, | |
| ListCtrl: _list_ctrl | |
| } | |
| })(); | |
| angular.module('mongolab', ['ngResource']). | |
| factory('Contacts', function($resource) { | |
| var Contacts = $resource( | |
| 'https://api.mongolab.com/api/1/databases/addressbook/collections/contacts/:id', | |
| { apiKey: 'RO27EEbdFsJfycTn_JUiAnr3qIcsgyxS' }, | |
| { update: { method: 'PUT' } } | |
| ); | |
| Contacts.prototype.update = function(cb) { | |
| return Contacts.update({id: this._id.$oid}, | |
| angular.extend({}, this, {_id:undefined}), cb); | |
| }; | |
| Contacts.prototype.delete = function(cb) { | |
| return Contacts.remove({id: this._id.$oid}, cb); | |
| }; | |
| return Contacts; | |
| }); | |
| angular.module('helpers', []). | |
| factory('Utils', function() { | |
| return { | |
| groupify : function(source, into) { | |
| var i, ch; | |
| for (i = source.length - 1; i >= 0; i--) { | |
| ch = source[i].firstName.charAt(0); | |
| into[ch] || (into[ch] = { | |
| label: ch, | |
| contacts: [] | |
| }); | |
| into[ch].contacts.push(source[i]); | |
| }; | |
| } | |
| } | |
| }); | |
| angular.module('android-addressbook', ['mongolab', 'helpers']). | |
| config(['$routeProvider', function($routeProvider, $locationProvider) { | |
| $routeProvider. | |
| when('/contacts', {templateUrl: 'list.html', controller: AddressBook.ListCtrl}). | |
| when('/contacts/starred', {templateUrl: 'starred.html', controller: AddressBook.ListCtrl}). | |
| when('/contacts/search', {templateUrl: 'search.html', controller: AddressBook.ListCtrl}). | |
| when('/contact/add', {templateUrl: 'edit.html', controller: AddressBook.DetailCtrl}). | |
| when('/contact/view/:id', {templateUrl: 'view.html', controller: AddressBook.DetailCtrl}). | |
| when('/contact/edit/:id', {templateUrl: 'edit.html', controller: AddressBook.DetailCtrl}). | |
| otherwise({redirectTo: '/contacts'}); | |
| }]); |
| @width: 480px; | |
| @base-fontsize: 16px; | |
| @icons-fontsize: 20px; | |
| @main-color: #51B4E3; | |
| @light-color: #A6D6EA; | |
| @bkg-color: #eee; | |
| @bottombar-bkg: #555; | |
| @text-color: #000; | |
| @icons-color: #fff; | |
| @list-bottomborder-color: #ddd; | |
| @labels-color: #6F6F6F; | |
| @topbar-height: 50px; | |
| @bottombar-height: 50px; | |
| @tabs-height: @topbar-height; | |
| @starred-caption-height: 40px; | |
| @profile-image-height: 180px; | |
| @titles-height: 30px; | |
| @list-padding: 20px; | |
| @list-item-height: 60px; | |
| @list-item-lineheight: 20px; | |
| @list-item-padding: 10px; | |
| @in-width: @width - (@list-padding * 2); | |
| @submenu-minwidth: 200px; | |
| @submenu-bkg: #eee; | |
| @submenu-shadow: #999; | |
| @submenu-bordercolor: #ccc; | |
| @submenu-item-height: 40px; | |
| @submenu-item-padding: 0 20px; | |
| .opacity(@v) { | |
| -webkit-opacity: @v; | |
| -moz-opacity: @v; | |
| -o-opacity: @v; | |
| opacity: @v; | |
| } | |
| .box-shadow(@x, @y, @h, @color) { | |
| -webkit-box-shadow: @x @y @h @color; | |
| -moz-box-shadow: @x @y @h @color; | |
| -o-box-shadow: @x @y @h @color; | |
| box-shadow: @x @y @h @color; | |
| } | |
| .border-box() { | |
| -webkit-box-sizing: border-box; | |
| -moz-box-sizing: border-box; | |
| -o-box-sizing: border-box; | |
| box-sizing: border-box; | |
| } | |
| /*****/ | |
| .fixed { | |
| position: fixed; | |
| } | |
| .absolute { | |
| position: absolute; | |
| } | |
| ul, ol, | |
| .zero { | |
| margin: 0; | |
| padding: 0; | |
| list-style-type: none; | |
| } | |
| .full { | |
| width: 100%; | |
| } | |
| .fixed.full, | |
| .absolute.full { | |
| width: @width; | |
| } | |
| .top { | |
| top: 0; | |
| } | |
| .bottom { | |
| bottom: 0; | |
| } | |
| .fleft { | |
| float: left; | |
| } | |
| .fright { | |
| float: right; | |
| } | |
| .overlay { | |
| background: #000; | |
| position: absolute; | |
| top: 0; bottom: 0; | |
| left: 0; right: 0; | |
| .opacity(0.6); | |
| } | |
| /*****/ | |
| body, | |
| html { | |
| height: 100%; | |
| } | |
| body { | |
| margin: 0; | |
| padding: 0; | |
| font: @base-fontsize Helvetica, sans-serif; | |
| color: @main-color; | |
| background: #000 url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAAECAYAAACp8Z5+AAAAJ0lEQVQIW2M0Njb+f+/ePQYYYBQUFPyvpKTEABMEC4BkYYJwAZggADGyDjN7QaaVAAAAAElFTkSuQmCC); | |
| } | |
| a { | |
| text-decoration: none; | |
| color: @text-color; | |
| } | |
| #scroller { | |
| width: 100%; | |
| .border-box; | |
| } | |
| .row { | |
| position: relative; | |
| margin: auto; | |
| width: @width; | |
| } | |
| .content { | |
| z-index: 1; | |
| position: fixed; | |
| background: @bkg-color; | |
| top: @topbar-height; | |
| bottom: @bottombar-height; | |
| width: @width; | |
| } | |
| .content.no-bottombar { | |
| bottom: 0; | |
| } | |
| .topbar { | |
| z-index: 2; | |
| height: @topbar-height; | |
| background: @main-color; | |
| .box-shadow(0, 2px, 10px, #888); | |
| } | |
| .bottombar { | |
| z-index: 2; | |
| height: @bottombar-height; | |
| background: @bottombar-bkg; | |
| } | |
| .title { | |
| font-size: @base-fontsize - 2%; | |
| color: @main-color; | |
| border-bottom: 2px solid @main-color; | |
| height: @titles-height; | |
| line-height: @titles-height; | |
| text-transform: uppercase; | |
| } | |
| /*****/ | |
| .lists { | |
| float: left; | |
| width: @in-width; | |
| padding: (@list-padding / 2) @list-padding (@list-padding / 2) @list-padding; | |
| } | |
| .lists.full { | |
| width: @width; | |
| padding: 0; | |
| } | |
| .list, | |
| .list-item, | |
| .list-item .item { | |
| float: left; | |
| width: 100%; | |
| position: relative; | |
| } | |
| .list-item .item { | |
| display: block; | |
| line-height: @list-item-lineheight; | |
| padding: @list-item-padding 0; | |
| border-top: 1px solid @list-bottomborder-color; | |
| } | |
| .list.single-fill .list-item .item { | |
| position: relative; | |
| padding: 0; | |
| height: @list-item-height; | |
| line-height: @list-item-height; | |
| } | |
| .list.single-fill .list-item.half { | |
| width: 50%; | |
| overflow: hidden; | |
| } | |
| .list.single-fill .list-item.half .item { | |
| overflow: hidden; | |
| height: @profile-image-height; | |
| border-top: none; | |
| } | |
| .list.single-fill .list-item.half .item.profile-image { | |
| left: 0; | |
| top: 0; | |
| } | |
| .list.single-fill .list-item.half .item.profile-image img { | |
| margin-top: -15%; | |
| } | |
| .list.single-fill .caption { | |
| height: @starred-caption-height; | |
| width: 100%; | |
| } | |
| .caption .text{ | |
| position: absolute; | |
| top: 0; bottom: 0; | |
| left: 0; right: 0; | |
| line-height: @starred-caption-height; | |
| padding: 0 20px; | |
| width: 100%; | |
| color: #fff; | |
| z-index: 2; | |
| .border-box; | |
| } | |
| .list-item:first-child .item { | |
| color: @text-color; | |
| border-top: none; | |
| } | |
| .list-item span.fleft { | |
| width: @in-width - @list-item-height; | |
| } | |
| .list-item span.fright { | |
| width: @list-item-height; | |
| height: @list-item-height; | |
| overflow: hidden; | |
| } | |
| .list-item span.fright img { | |
| float: right; | |
| } | |
| .list-item .item .label { | |
| display: block; | |
| text-transform: uppercase; | |
| font-size: @base-fontsize - 2%; | |
| color: #666; | |
| } | |
| /*****/ | |
| .tabs > li > a, | |
| .tabs > li { | |
| float: left; | |
| } | |
| .tabs > li { | |
| width: 50%; | |
| height: @tabs-height - 5px; | |
| } | |
| .tabs.three > li { | |
| width: 33.33%; | |
| } | |
| .tabs > li:hover, | |
| .tabs > li.active { | |
| border-bottom: 5px solid @icons-color; | |
| } | |
| .tabs > li > a { | |
| width: 100%; | |
| height: @tabs-height - 20%; | |
| line-height: @tabs-height - 20%; | |
| margin-top: (@tabs-height - (@tabs-height - 20%)) / 2; | |
| text-align: center; | |
| border-right: 1px solid @light-color; | |
| } | |
| .tabs > li:last-child > a { | |
| border-right: none; | |
| } | |
| /*****/ | |
| .icon > a { | |
| color: @icons-color; | |
| font-size: @icons-fontsize; | |
| } | |
| .bar .icn, | |
| .bar .icn > a { | |
| display: block; | |
| width: @bottombar-height; | |
| height: @bottombar-height; | |
| line-height: @bottombar-height; | |
| text-align: center; | |
| } | |
| .bar .icn { | |
| position: absolute; | |
| z-index: 2; | |
| } | |
| .bar .icn.left { | |
| left: 0; | |
| } | |
| .bar .icn.right { | |
| right: 0; | |
| } | |
| .bar .icn.right.sec { | |
| right: 60px; | |
| } | |
| .bar .icn.center { | |
| left: 50%; | |
| margin-left: -(@bottombar-height / 2); | |
| } | |
| .bar .icn.full { | |
| z-index: 1; | |
| float: left; | |
| padding-left: 60px; | |
| width: auto; | |
| } | |
| .bar .icn.full.centred { | |
| padding-left: 0; | |
| float: none; | |
| width: 100%; | |
| } | |
| .bar .icn.action, | |
| .bar .icn.action a { | |
| width: auto; | |
| font-size: @base-fontsize; | |
| } | |
| .bar .icn.action a span { | |
| font-size: @base-fontsize + 6%; | |
| } | |
| .bar .icn.action a { | |
| padding: 0 10px; | |
| } | |
| .bar .icn.action a span{ | |
| padding-right: 10px; | |
| } | |
| .contact-name { | |
| color: @icons-color; | |
| font-size: @base-fontsize + 2%; | |
| font-weight: bold; | |
| } | |
| /*****/ | |
| .submenu { | |
| display: none; | |
| position: absolute; | |
| text-align: left; | |
| min-width: @submenu-minwidth; | |
| background: @submenu-bkg; | |
| right: @list-padding / 2; | |
| .box-shadow(0, 2px, 5px, @submenu-shadow); | |
| } | |
| .show-submenu .submenu { | |
| display: block; | |
| } | |
| .submenu li a { | |
| height: @submenu-item-height; | |
| line-height: @submenu-item-height; | |
| padding: @submenu-item-padding; | |
| display: block; | |
| text-transform: capitalize; | |
| } | |
| .submenu li { | |
| border-bottom: 1px solid @submenu-bordercolor; | |
| } | |
| .submenu li:last-child a { | |
| border-bottom:none; | |
| } | |
| /*****/ | |
| .profile-image { | |
| position: relative; | |
| overflow: hidden; | |
| height: @profile-image-height; | |
| width: @width; | |
| left: -@list-padding; | |
| top: -(@list-padding / 2); | |
| } | |
| .profile-image img { | |
| position: absolute; | |
| margin-top: -40%; | |
| width: 100%; | |
| } | |
| .profile-image.open { | |
| height:auto; | |
| } | |
| .profile-image.open img { | |
| position: static; | |
| margin-top: 0; | |
| } | |
| /******/ | |
| .form .title { | |
| padding-left: 10px; | |
| .border-box; | |
| } | |
| .form .list-item:last-child { | |
| margin-bottom: 20px; | |
| } | |
| .form .form-item { | |
| position: relative; | |
| height: auto; | |
| min-height: auto; | |
| border-top: none; | |
| width: 100%; | |
| padding: 10px; | |
| .border-box; | |
| } | |
| .form .list-item button { | |
| border: none; | |
| background: none; | |
| margin: 0; | |
| text-transform: uppercase; | |
| font-size: @base-fontsize - 2%; | |
| color: #666; | |
| } | |
| .form .list-item.action button { | |
| padding: 5px 10px 0; | |
| margin: 10px 0 0; | |
| } | |
| .form .form-item.action { | |
| text-align: center; | |
| } | |
| .form .form-item.action button { | |
| font-size: @base-fontsize + 10%; | |
| } | |
| .form .form-item input, | |
| .form .form-item textarea { | |
| width: 100%; | |
| border: none; | |
| background: none; | |
| margin: 0; | |
| padding: 7px 0 3px; | |
| } | |
| .form .form-item .form-item-decorator { | |
| width: 99%; | |
| height: 5px; | |
| position: absolute; | |
| left: 0; | |
| bottom: 0; | |
| border-bottom: 1px solid @list-bottomborder-color; | |
| border-left: 1px solid @list-bottomborder-color; | |
| border-right: 1px solid @list-bottomborder-color; | |
| } | |
| .form .form-item input:focus, | |
| .form .form-item textarea:focus { | |
| outline: none | |
| } | |
| form .form-item input:focus + .form-item-decorator, | |
| form .form-item textarea:focus + .form-item-decorator { | |
| border-color: @main-color; | |
| } | |
| form .form-item input.ng-invalid + .form-item-decorator { | |
| border-color: red; | |
| } | |
| .form .form-item.field-left { | |
| width: 62%; | |
| } | |
| .form .form-item.field-right { | |
| width: 23%; | |
| } | |
| .form .form-item.field-right-right { | |
| width: 15%; | |
| padding: 10px 0 | |
| } | |
| .form .form-item.field-left.img { | |
| width: 70%; | |
| } | |
| .form .form-item.field-right.img { | |
| width: 30%; | |
| padding: (@list-padding / 2) 0; | |
| } | |
| .form .form-item.field-right img { | |
| float: right; | |
| padding: 0 @list-padding; | |
| } | |
| .bar .icn.full.contact-name { | |
| text-align: left; | |
| max-width: 50%; | |
| overflow: hidden; | |
| } | |
| .bar .icn.full.contact-name.form { | |
| width: @width - @list-padding; | |
| max-width: @width - @list-padding; | |
| .border-box; | |
| } | |
| .contact-name.form .form-item { | |
| height: @topbar-height - (@list-padding / 2); | |
| padding-top: 0; | |
| } | |
| .contact-name.form .form-item .cancel { | |
| position: absolute; | |
| right: @list-padding / 2; | |
| top: 0; | |
| } | |
| .contact-name.form .form-item input { | |
| color: @icons-color; | |
| } | |
| .contact-name.form .form-item ::-webkit-input-placeholder { | |
| color: @icons-color; | |
| } | |
| .contact-name.form .form-item :-moz-placeholder { | |
| color: @icons-color; | |
| } | |
| .contact-name.form .form-item ::-moz-placeholder { | |
| color: @icons-color; | |
| } | |
| .contact-name.form .form-item placeholder { | |
| color: @icons-color; | |
| } | |
| /*********************/ | |
| @media only screen and (max-device-width : 480px) { | |
| .fixed.full, | |
| .absolute.full, | |
| .row, | |
| .content, | |
| .lists.full { | |
| width: 100%; | |
| } | |
| .profile-image { | |
| width: 108%; | |
| } | |
| .lists { | |
| padding: 2% 4% 2% 4%; | |
| width: 92%; | |
| } | |
| .lists { | |
| width: 92%; | |
| } | |
| .list-item span.fleft { | |
| width: 80%; | |
| } | |
| .list-item span.fright { | |
| width: 20%; | |
| } | |
| .submenu { | |
| right: 20%; | |
| } | |
| .profile-image { | |
| left: -4%; | |
| margin-top: -2%; | |
| } | |
| .form .form-item.field-right img { | |
| padding: 0 2%; | |
| } | |
| .list.single-fill .list-item.half .item.profile-image img { | |
| margin-top: -5%; | |
| } | |
| .list.single-fill .list-item.half .item.profile-image img { | |
| margin-top: -5%; | |
| } | |
| .bar .icn.full.contact-name.form { | |
| width: 96%; | |
| } | |
| .contact-name.form .form-item .cancel { | |
| right: 2%; | |
| } | |
| } |