<!-- React component container -->
<div id='device-cards'></div>
@import "nib"

//
// Colors
//-----------------------------------------------------
$grey         = #69747e 
$grey-light   = #ecf0f1
$grey-medium  = #6c7a89
$grey-dark    = #22313F
$blue         = #3498db
$red          = #c0392b
$green        = #27ae60
$purple       = #9b59b6
$orange       = #f39c12


//
// Typography
//-----------------------------------------------------
@import url('https://fonts.googleapis.com/css?family=Lato:100,300,400,700')


//
// Globals
//-----------------------------------------------------
* {
  box-sizing border-box
  margin 0
  padding 0
}
html, body {
  background $grey-light
  font-family 'Lato', sans-serif
}
ul, ol, li {
  list-style-type none
}
a {
  text-decoration none
}
h1, h2, h3, h4, h5, h6 {
  margin 0
  padding 0
  font-weight normal
}


//
// Variables & animations
//-----------------------------------------------------
$card-width      = 300px
$card-height     = 400px
$masthead-height = 220px
$easing          = cubic-bezier(0.645, 0.045, 0.355, 1)

@keyframes shake {
  0% {
    transform translateX(7px)
  }
  15% {
    transform translateX(-7px)
  }
  30% {
    transform translateX(5px)
  }
  45% {
    transform translateX(-5px)
  }
  60% {
    transform translateX(3px)
  }
  75% {
    transform translateX(-3px)
  }
  100% {
    transform translateX(0px)
  }
}
.shake {
  animation-name shake
  animation-duration 450ms
}

//
// Component UI
//-----------------------------------------------------
.ui-card {
  width $card-width
  height $card-height
  background white
  border 2px solid darken($grey-light, 5%)
  position relative
  border-radius 8px
  overflow hidden
  
  // For codepen
  position absolute
  top 50%
  left 50%
  margin-top -($card-height / 2)
  margin-left -($card-width / 2) 
}
.ui-card .toggle {
  position absolute
  top 10px
  right 10px
}
.ui-card section {
  width 100%
  height 100%
  position absolute
  transition all 200ms ease-in-out
}
.ui-card .content {
  left 0
}


//
// Side bar toggle switch
//
.ui-card .toggle i {
  color white
  transition all 300ms $easing
}
.ui-card.sidebar-open .toggle i {
  color $grey-dark
  transform rotateZ(180deg)
}


//
// Sidebar styles
//
.ui-card .sidebar {
  left 100%
  background white
  box-shadow none
  transition all 300ms $easing
  overflow hidden
}

//
// Sidebar toggled animation
//
.ui-card.sidebar-open .content {
  left -10% 
}
.ui-card.sidebar-open .sidebar {
  left 10%
  box-shadow 0px 0px $card-width 100px rgba(0, 0, 0, 0.7)
}

.ui-card nav {
  width 90% // this accounts for the 10% 'margin' on the right when shown
  padding-top 40px
}
.ui-card nav li {
  border-bottom 1px solid $grey-light
}
.ui-card nav li i {
  display inline-block
  width 30px
}
.ui-card nav li a {
  display block
  padding 20px
  padding-left 30px
  color $grey-medium
}
.ui-card nav li a:hover {
  border-left 4px solid $blue 
  padding-left 26px
  color $grey-dark
}
.ui-card .disconnect {
  line-height 117px
  left 0px
}
.ui-card .disconnect,
.ui-card .reauth {
  width 90%
  height 117px // Arbitrary height... should refactor this area to flex box
  text-align center
  position absolute
  bottom 0px
  transition all 300ms $easing
}
.ui-card .btn {
  font-size .8em
}
.ui-card .btn-disconnect {
  color $red
  padding 10px 30px
}
.ui-card .btn-disconnect:hover {
  color white
  background-color $red
  border-radius 6px // This would be in a global
}

//
// Re-auth area
//
.ui-card .reauth {
  padding-top 20px
  left 100%
}
.ui-card .reauth h3 {
  font-size 15px
  margin-bottom 7px
  color $red
}
.ui-card .reauth input {
  border-radius 4px
  border 1px solid lighten($grey-medium, 50%)
  padding 5px
  margin-bottom 7px
}
.ui-card .reauth input:focus {
  outline none
  border 2px solid $blue
  margin-top -1px
  margin-bottom 6px
}
.ui-card .btn-cancel {
  color darken($grey-light, 20%)
}

// 
// Reauth toggled state
// 
.ui-card .sidebar.reauth-toggled .disconnect {
  left -100%
}
.ui-card .sidebar.reauth-toggled .reauth {
  left 0px
}

// 
// Card content area
// 
.ui-card .masthead {
  width 100%
  height $masthead-height
  position relative
  background $grey-dark
}
.ui-card .masthead h1 {
  height $masthead-height
  color white
  line-height ($masthead-height - 20)
  text-align center
  font-weight 300
  font-size 28px
}
.ui-card .device-icon {
  background $blue
  width 90px
  height 90px
  border-radius 50%
  padding 4.5%
  position absolute
  left 50%
  margin-left -45px
  bottom -45px
  text-align center
}
.ui-card .device-info {
  width 100%
  position absolute
  top ($masthead-height + 30%)
}
.ui-card .device-icon i {
  color white
  font-size 66px
}
.ui-card .device-space {
  width 100%
  height 60px
  text-align center
}
.ui-card .device-space h3 {
  color $grey-medium
  font-size 17px
  margin-bottom 15px
}
.ui-card .available-space {
  background $grey-light
  width 80%
  margin 0 auto
  height 10px
  position relative
  border-radius 20px
  overflow hidden
}

// Hardcoded for prototype
.ui-card .used-space--photos,
.ui-card .used-space--videos {
  height 100%
  position absolute
  border-radius 20px
}
.ui-card .used-space--photos {
  width 70%
  background $green
}
.ui-card .used-space--videos {
  width 30%
  background $orange
}

.ui-card .device-legend {
  text-align center
  font-size 11px
}
.ui-card .device-legend li {
  display inline-block
  margin-right 20px
  color $grey-medium
}
.ui-card .device-legend li:last-child {
  margin-right 0px
}
.ui-card .device-legend i {
  display inline-block
  position relative
  top -1px
  font-size 9px
  margin-right 3px
}
.ui-card .device-legend i.photos {
  color $green
}
.ui-card .device-legend i.videos {
  color $orange
}
View Compiled
/** @jsx React.DOM */

//
// Main device wrapper
// NOTE: Holding menu toggle state here (eventually)
//--------------------------------------------------------
var DeviceCard = React.createClass({
  render: function() {
    return (
      <div className='ui-card'>
        <Device_section__info data={this.props.data} />
        <Device_section__sideBarMenu />
        <Device_action__toggleMenu />
      </div>
    );
  }
});


//
// Device information section wrapper
//--------------------------------------------------------
var Device_section__info = React.createClass({
  render: function() {
    return (
      <section className='content'>
        <Device_section__mastHead data={this.props.data} />
        <Device_section__freeSpace />
      </section>
    );
  }
});


//
// Device side bar menu wrapper
//--------------------------------------------------------
var Device_section__sideBarMenu = React.createClass({
  render: function() {
    return (
      <section className='sidebar'>
        <nav>
          <Device_section__sideBarNav />
          <Device_section__sideBarRemoveConnection />
        </nav>
      </section>
    );      
  }
});


//
// Device side bar nav list
//--------------------------------------------------------
var Device_section__sideBarNav = React.createClass({
  render: function() {
    return (

      // TODO: Each item here should be visible based on flags
      //       I.e No photos? Should we show edit photos? 
      <ul>
        <li>
          <a href="#"><i className='fa fa-wifi'></i>Wireless Settings</a>
        </li>
        <li>
          <a href="#"><i className='fa fa-info-circle'></i>Device Information</a>
        </li>
        <li>
          <a href="#"><i className='fa fa-photo'></i>Edit Photos</a>
        </li>
        <li>
          <a href="#"><i className='fa fa-video-camera'></i>Edit Videos</a>
        </li>
      </ul>
    );
  }
});


//
// Device side bar delete connection \ reauth 
//--------------------------------------------------------
var Device_section__sideBarRemoveConnection = React.createClass({
  render: function() {
    return (
      <span>
        <div className='disconnect'>
          <a href='#' className='btn btn-disconnect'>Disconnect Device</a>
        </div>
        <div className='reauth'>
          <h3>Re-enter your password</h3>
          <input type='password' />
          <p>
            <a href="#" className='btn btn-cancel js-reAuth'>Cancel</a>
          </p>
        </div>
      </span>
    );
  }
});


//
// Device actions toggle switch
//--------------------------------------------------------
var Device_action__toggleMenu = React.createClass({
  handleClick: function() {
    // TODO: Do this in the React way. 
    $(this.getDOMNode()).closest('.ui-card').toggleClass('sidebar-open');
  },
  render: function() {
    return (
      <div className='toggle'>
        <a href='#' onClick={this.handleClick}><i className="fa fa-cog"></i></a>
      </div>
    );      
  }
});


//
// Masthead
//
var Device_section__mastHead = React.createClass({
  render: function() {
    return (
      <header className='masthead'>
        <h1>{this.props.data.deviceName}</h1>
        <div className='device-icon'>
          <i className='fa fa-mobile-phone'></i>
        </div>
      </header>
    );
  }
});

//
// Free space module
//
var Device_section__freeSpace = React.createClass({
  render: function() {
    return (

      // This is all static for now
      // Todo: Populate this with data, and animate accordingly.
      //       Adding some actual values probably wouldn't hurt either. 
      <article className='device-info'>
        <div className='device-space'>
          <h3>Free Space</h3>
            <div className='available-space'>
            <div className="used-space--photos"></div>
            <div className="used-space--videos"></div>
          </div>
        </div>
        <ul className='device-legend'>
          <li><i className="fa fa-circle videos"></i> Videos</li>
          <li><i className="fa fa-circle photos"></i> Photos</li>
          <li><i className="fa fa-circle available"></i> Available</li>
        </ul>
      </article>
    );
  }
});


//
// Fake and totally arbitrary data
//--------------------------------------------------------
var device_data = {
  deviceType       : 'iphone',
  deviceName       : 'iPhone 6',
  availableSpace   : 2048,  // megabytes
  photosTotalSpace : 768, // megabytes
  videosTotalSpace : 384  // megabytes
}


//
// Render this ish
//--------------------------------------------------------
React.renderComponent(
  <DeviceCard data={device_data}/>,
  document.getElementById('device-cards')
);

External CSS

  1. //cdnjs.cloudflare.com/ajax/libs/font-awesome/4.2.0/css/font-awesome.min.css

External JavaScript

  1. //cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js
  2. https://codepen.io/chriscoyier/pen/yIgqi.js
  3. https://fb.me/react-0.11.2.js
  4. https://fb.me/JSXTransformer-0.11.2.js