A contacts list based on a video from Google's Material Design spec.
Forked from Kyle Edwards's Pen Meaningful Transitions.
| <!-- | |
| Based on the contacts video from Meaningful Transitions | |
| https://www.google.com/design/spec/animation/meaningful-transitions.html# | |
| --> | |
| <div class="app-wrapper"> | |
| <header class="app-bar"> | |
| <button id="menuToggle" class="app-bar-button menu-toggle menu-is-closed"><i class="fa fa-bars"></i></button> | |
| <h1 id="appHeadline" class="app-headline">All Contacts</h1> | |
| <button id="sortToggle" class="app-bar-button sort-toggle"><i class="fa fa-sort-alpha-asc"></i></button> | |
| </header> | |
| <div class="app-body"> | |
| <table id="contactList" class="contact-list"> | |
| <tbody> | |
| </tbody> | |
| </table> | |
| <table id="contactInfo" class="contact-info"> | |
| <tbody> | |
| <tr id="contactUsername" class="contact-info-item"><td class="contact-info-icon"><i class="fa fa-comment-o"></i></td><td class="contact-info-detail">joedoe</td></tr> | |
| <tr id="contactEmail" class="contact-info-item"><td class="contact-info-icon"><i class="fa fa-envelope-o"></i></td><td class="contact-info-detail">john.smith@email.com</td></tr> | |
| <tr id="contactHomeNumber" class="contact-info-item"><td class="contact-info-icon"><i class="fa fa-phone"></i></td><td class="contact-info-detail">(555) 987-1234</td></tr> | |
| <tr id="contactWorkNumber" class="contact-info-item"><td class="contact-info-icon"><i class="fa fa-building-o"></i></td><td class="contact-info-detail">(555) 987-1234</td></tr> | |
| <tr id="contactAddress" class="contact-info-item"><td class="contact-info-icon"><i class="fa fa-home"></i></td><td class="contact-info-detail">123 Elm Street</td></tr> | |
| </tbody> | |
| </table> | |
| </div> | |
| </div> |
A contacts list based on a video from Google's Material Design spec.
Forked from Kyle Edwards's Pen Meaningful Transitions.
| var contactInformation = [{'firstName': 'Micheal', 'lastName': 'Carswell', 'color': randomColor({luminosity : 'light'})}, | |
| { 'firstName': 'Jed', 'lastName': 'Cherry', 'color': randomColor({luminosity : 'light'})}, | |
| { 'firstName': 'Freddie', 'lastName': 'Crimmins', 'color': randomColor({luminosity : 'light'})}, | |
| { 'firstName': 'Dimple', 'lastName': 'Deloatch', 'color': randomColor({luminosity : 'light'})}, | |
| { 'firstName': 'Tomas', 'lastName': 'Duhn', 'color': randomColor({luminosity : 'light'})}, | |
| { 'firstName': 'Coralee', 'lastName': 'Earheart', 'color': randomColor(), 'color': randomColor({luminosity : 'light'})}, | |
| { 'firstName': 'Solomon', 'lastName': 'Magruder', 'color': randomColor({luminosity : 'light'})}, | |
| { 'firstName': 'Antionette', 'lastName': 'May', 'color': randomColor({luminosity : 'light'})}, | |
| { 'firstName': 'Illa', 'lastName': 'Schwindt', 'color': randomColor({luminosity : 'light'})}, | |
| { 'firstName': 'Jesica', 'lastName': 'Utt', 'color': randomColor({luminosity : 'light'})}]; | |
| var contactList = document.querySelector('#contactList tbody'); | |
| function addContact(contactInfo) { | |
| var contact = document.createElement('tr'); | |
| contact.classList.add('contact'); | |
| var contactImage = document.createElement('td'); | |
| contactImage.classList.add('contact-image'); | |
| var contactImg = document.createElement('div'); | |
| contactImg.style.backgroundColor = contactInfo['color']; | |
| contactImg.setAttribute('data-image-color', contactInfo['color']); | |
| var contactName = document.createElement('td'); | |
| contactName.classList.add('contact-name'); | |
| var firstName = document.createElement('span'); | |
| firstName.classList.add('first-name'); | |
| firstName.appendChild(document.createTextNode(contactInfo['firstName'])); | |
| var lastName = document.createElement('span'); | |
| lastName.classList.add('last-name'); | |
| lastName.appendChild(document.createTextNode(contactInfo['lastName'])); | |
| contactImage.appendChild(contactImg); | |
| contact.appendChild(contactImage); | |
| contactName.appendChild(firstName); | |
| contactName.appendChild(document.createTextNode(' ')); | |
| contactName.appendChild(lastName); | |
| contact.appendChild(contactName); | |
| contactList.appendChild(contact); | |
| } | |
| for(var i = 0; i < contactInformation.length; i++) { | |
| addContact(contactInformation[i]); | |
| } | |
| function focusSelectedContact(event) { | |
| var currentTarget = event.currentTarget, | |
| appBody = document.querySelector('.app-body'), | |
| rect = currentTarget.getBoundingClientRect(), | |
| appBarRect = appBody.getBoundingClientRect(), | |
| translate = appBarRect.top - rect.top + 171, | |
| root = document.querySelector('html'), | |
| menuToggleIcon = document.querySelector('#menuToggle i'), | |
| contactInfo = document.querySelector('.contact-info'); | |
| currentTarget.classList.remove('previously-selected'); | |
| currentTarget.classList.add('selected-contact'); | |
| root.classList.add('hide-contacts'); | |
| root.classList.remove('show-contacts'); | |
| currentTarget.style.webkitTransform = 'translateY(' + translate +'px)'; | |
| currentTarget.style.transform = 'translateY(' + translate +'px)'; | |
| currentTarget.offsetHeight; // Force a redraw so the animation works | |
| var color = currentTarget.querySelector('.contact-image div').getAttribute('data-image-color'); | |
| appBody.style.backgroundImage = 'linear-gradient(' + color + ' 0%, #fff 100%)'; | |
| appBody.style.backgroundPosition = '0 0'; | |
| appBody.style.overflow = 'hidden'; | |
| menuToggleIcon.classList.remove('fa-bars'); | |
| menuToggleIcon.classList.add('fa-arrow-left'); | |
| contactInfo.classList.add('visible'); | |
| } | |
| [].forEach.call(document.querySelectorAll('.contact'), function(contact) { | |
| contact.addEventListener('click', focusSelectedContact) | |
| }); | |
| function showAllContacts() { | |
| var appBody = document.querySelector('.app-body'), | |
| selectedContact = document.querySelector(".selected-contact"), | |
| menuToggleIcon = document.querySelector('#menuToggle i'), | |
| contactInfo = document.querySelector('.contact-info'); | |
| selectedContact.style.webkitTransform = ''; | |
| selectedContact.style.transform = ''; | |
| selectedContact.offsetHeight; // Force a redraw so the animation works | |
| appBody.style.backgroundPosition = ''; | |
| appBody.style.overflow = 'auto'; | |
| menuToggleIcon.classList.add('fa-bars'); | |
| menuToggleIcon.classList.remove('fa-arrow-left'); | |
| contactInfo.classList.remove('visible'); | |
| setTimeout(function() { | |
| var root = document.querySelector('html'); | |
| root.classList.add('show-contacts'); | |
| root.classList.remove('hide-contacts'); | |
| selectedContact.classList.remove('selected-contact'); | |
| }, 250); | |
| } | |
| document.querySelector('#menuToggle').addEventListener('click', showAllContacts); | |
| @import url(http://fonts.googleapis.com/css?family=Roboto:400,700); | |
| ::-webkit-scrollbar { | |
| display: none; | |
| } | |
| body { | |
| background-color: #f9f9f9; | |
| font-family: 'Roboto', sans-serif; | |
| -webkit-user-select: none; | |
| -moz-user-select: none; | |
| -ms-user-select: none; | |
| } | |
| .app-wrapper { | |
| background-color: #fff; | |
| font-family: sans-serif; | |
| margin: 50px auto; | |
| overflow: hidden; | |
| position: relative; | |
| width: 400px; | |
| } | |
| .app-bar { | |
| background-color: #f2f2f2; | |
| box-shadow: 0 2px 2px #c6c6c6; | |
| box-sizing: border-box; | |
| padding: 15px 70px; | |
| position: absolute; | |
| width: 100%; | |
| z-index: 3; | |
| transition: background-color 500ms, box-shadow 500ms; | |
| } | |
| .hide-contacts .app-bar { | |
| background-color: transparent; | |
| box-shadow: 0 0 0 transparent; | |
| } | |
| .hide-contacts #menuToggle { | |
| cursor: pointer; | |
| } | |
| .app-headline { | |
| color: #5f5f5f; | |
| cursor: default; | |
| display: inline-block; | |
| font-family: 'Roboto', sans-serif; | |
| font-size: 24px; | |
| font-weight: normal; | |
| margin: 0; | |
| opacity: 1; | |
| transition: opacity 500ms; | |
| } | |
| .hide-contacts .app-headline { | |
| opacity: 0; | |
| } | |
| .app-bar-button { | |
| background: none; | |
| border: none; | |
| color: #b1b1b1; | |
| height: 30px; | |
| outline: none; | |
| padding: 2px 0 3px; | |
| text-shadow: 0 0 transparent; | |
| transition: color 500ms, text-shadow 500ms; | |
| width: 30px; | |
| } | |
| .app-bar-button:hover { | |
| color: #c1c1c1; | |
| } | |
| .app-bar-button:active { | |
| color: #919191; | |
| } | |
| .hide-contacts .app-bar-button { | |
| color: #fff; | |
| text-shadow: 1px 1px #c1c1c1; | |
| } | |
| #menuToggle .fa { | |
| font-size: 2.25em; | |
| } | |
| #sortToggle .fa { | |
| font-size: 1.75em; | |
| } | |
| .menu-toggle { | |
| left: 13px; | |
| position: absolute; | |
| top: calc(50% - 13px); | |
| } | |
| .sort-toggle { | |
| position: absolute; | |
| right: 13px; | |
| top: calc(50% - 13px); | |
| } | |
| .app-body { | |
| background-image: linear-gradient(transparent, transparent); | |
| background-position: 0 -300px; | |
| background-repeat: no-repeat; | |
| background-size: 100% 238px; | |
| height: 450px; | |
| -ms-overflow-style: none; | |
| overflow-y: auto; | |
| overflow-x: hidden; | |
| padding: 62px 0 0; | |
| transition: background-position 500ms; | |
| } | |
| .app-body::-webkit-scrollbar { | |
| display: none; | |
| } | |
| .contact-list { | |
| display: block; | |
| padding: 2px; | |
| } | |
| .contact-list tbody { | |
| display: -webkit-flex; | |
| display: -ms-flex; | |
| display: flex; | |
| -webkit-flex-wrap: wrap; | |
| -ms-flex-wrap: wrap; | |
| flex-wrap: wrap; | |
| } | |
| .contact { | |
| border-bottom: 1px solid #f5f5f5; | |
| cursor: pointer; | |
| position: relative; | |
| display: block; | |
| -webkit-flex: 1 0 100%; | |
| -ms-flex: 1 0 100%; | |
| flex: 1 0 100%; | |
| opacity: 1; | |
| overflow: hidden; | |
| -webkit-transition-property: opacity, top, -webkit-transform; | |
| -webkit-transition-duration: 500ms; | |
| transition-property: opacity, top, transform; | |
| transition-duration: 500ms; | |
| -webkit-transform: translateY(0); | |
| transform: translateY(0); | |
| } | |
| .contact-image div { | |
| border-radius: 50%; | |
| display: inline-block; | |
| height: 35px; | |
| margin: 10px 13px; | |
| width: 35px; | |
| vertical-align: middle; | |
| } | |
| .contact-name { | |
| color: #515151; | |
| cursor: inherit; | |
| font-family: 'Roboto', sans-serif; | |
| font-size: 16px; | |
| position: relative; | |
| z-index: 2; | |
| -webkit-transition: -webkit-transform 500ms; | |
| transition: transform 500ms; | |
| } | |
| .contact-name .last-name { | |
| color: #4d4d4d; | |
| font-weight: bold; | |
| } | |
| .selected-contact { | |
| cursor: default; | |
| pointer-events: none; | |
| } | |
| .selected-contact .contact-name { | |
| -webkit-transform: scale(1.2) translateX(9px); | |
| transform: scale(1.2) translateX(9px); | |
| } | |
| .hide-contacts .contact:not(.selected-contact) { | |
| pointer-events: none; | |
| -webkit-transform: translateY(50px); | |
| transform: translateY(50px); | |
| opacity: 0; | |
| } | |
| .contact-info { | |
| background-color: #fff; | |
| font-size: 18px; | |
| min-height: 20px; | |
| opacity: 0; | |
| position: absolute; | |
| top: 233px; | |
| -webkit-transform: translateY(275px); | |
| transform: translateY(275px); | |
| -webkit-transition: -webkit-transform 500ms, opacity 1000ms; | |
| transition: transform 500ms, opacity 1000ms; | |
| width: 100%; | |
| z-index: 1; | |
| } | |
| .contact-info.visible { | |
| opacity: 1; | |
| -webkit-transform: translateY(0); | |
| transform: translateY(0); | |
| } | |
| .contact-info { | |
| color: #484848; | |
| } | |
| .contact-info-item { | |
| border-bottom: 1px solid #f5f5f5; | |
| display: block; | |
| } | |
| .contact-info-icon { | |
| height: 35px; | |
| padding: 10px 13px; | |
| width: 35px; | |
| text-align: center; | |
| } | |
| .contact-info-icon i { | |
| font-size: 1.5em; | |
| vertical-align: middle; | |
| } | |
| .contact-info-detail { | |
| padding-left: 5px; | |
| } |