123

Pen Settings

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

+ add another resource

You're using npm packages, so we've auto-selected Babel for you here, which we require to process imports and make it all work. If you need to use a different JavaScript preprocessor, remove the packages in the npm tab.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Use npm Packages

We can make npm packages available for you to use in your JavaScript. We use webpack to prepare them and make them available to import. We'll also process your JavaScript with Babel.

⚠️ This feature can only be used by logged in users.

Code Indentation

     

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

HTML Settings

Here you can Sed posuere consectetur est at lobortis. Donec ullamcorper nulla non metus auctor fringilla. Maecenas sed diam eget risus varius blandit sit amet non magna. Donec id elit non mi porta gravida at eget metus. Praesent commodo cursus magna, vel scelerisque nisl consectetur et.

            
              .app
  .app-day-container.hidden
    .day-header.day-header--large
      .day-header-bg
      .day-header-close
      .day-header-content
        .day-header-title
          .day-header-title-day 24
          .day-header-title-month June
        .day-header-event Midsummer day
    .day-content
      p Lorem ipsum dolor sit amet, consectetur adipisicing elit. Adipisci blanditiis commodi accusamus dolores itaque repudiandae, voluptates.
      .img
      p Lorem ipsum dolor sit amet, consectetur adipisicing elit. Similique aut rem ipsa consectetur voluptate error nam repellat iusto amet facilis voluptatem alias dolorum animi commodi ea, impedit consequuntur magni nihil!
       .img
      p Lorem ipsum dolor sit amet, consectetur adipisicing elit. Similique aut rem ipsa consectetur voluptate error nam repellat iusto amet facilis voluptatem alias dolorum animi commodi ea, impedit consequuntur magni nihil!
       .img
      p Lorem ipsum dolor sit amet, consectetur adipisicing elit. Similique aut rem ipsa consectetur voluptate error nam repellat iusto amet facilis voluptatem alias dolorum animi commodi ea, impedit consequuntur magni nihil!
  .app-header
    .nav-btn
    .month June
    .header-right-wrapper
      .menu-btn
  .app-calendar
    .calendar-row.day-row
      - var days = ['m', 't', 'w', 't', 'f', 's', 's']
      each day in days
        .day.day-name=day.toUpperCase()
    .calendar-row
      .day &nbsp;
      .day &nbsp;
      .day 1
      .day.event.blue(data-day="2" data-event="Pay the bills") 2
      .day 3
      .day 4
      .day 5
    .calendar-row
      .day 6
      .day.event.purple(data-day="7" data-event="Doctors appointment") 7
      .day 8
      .day 9
      .day 10
      .day 11
      .day 12
    .calendar-row
      .day 13
      .day 14
      .day 15
      .day 16
      .day 17
      .day 18
      .day 19
    .calendar-row
      .day 20
      .day 21
      .day.event.blue(data-day="22" data-event="Miranda's birthday") 22
      .day 23
      .day.event.pink(data-day="24" data-event="Midsummer day") 24
      .day 25
      .day.event.purple(data-day="26" data-event="Meeting with Patrick") 26
    .calendar-row
      .day 27
      .day 28
      .day 29
      .day 30
      .day
      .day
      .day
  .app-divider
  .app-events
    .app-event
      .event-date.blue 2
      .event-title Pay the bills
    .app-event
      .event-date.purple 7
      .event-title Doctors appointment
    .app-event
      .event-date.blue 22
      .event-title Miranda's birthday
    .app-event
      .event-date.pink 24
      .event-title Midsummer day
    .app-event
      .event-date.purple 26
      .event-title Meeting with Patrick
            
          
!
            
              $main = #2C3144
$accent = #FA3275
$day-text = darken(#778489, 25%)
$faded-text = #869BA1

$day-blue = #00AFF2
$day-purple = #9977CC
$day-pink = #FA3275

// Original dimensions taken from the animation
// Scaling down just a bit to fit it on screen
$app-scale = .75
$app-width = 400px * $app-scale
$app-height = ($app-width / 9) * 16
$app-gutter-size = 16px

$app-header-height = 46px
$app-day-header-large = 200px

// Close
$app-close-btn-size = 18px
$app-close-btn-thickness = 2px

// Hamburger
$nav-btn-width = 18px
$nav-btn-height = 2px

// Kebab
$menu-btn-size = 4px

$calendar-day-size = 20px
$calendar-day-padding = 14px

*
*:before
*:after
  box-sizing border-box

body
  display flex
  align-items center
  justify-content center
  height 100vh
  overflow hidden
  font-family Roboto, sans-serif
  background $main

.app
  position relative
  width $app-width
  height $app-height
  border-radius 3px
  overflow hidden
  background white
  
.app-header
  display flex
  align-items center
  width 100%
  height $app-header-height
  padding $app-gutter-size
  
  .nav-btn
    $bar-offset = $nav-btn-height + 3px
    position relative
    display inline-block
    margin-top -1px // Every damn time
    width $nav-btn-width
    height $nav-btn-height
    background $main
    border-radius 3px
    
    &:before
    &:after
      content ''
      display block
      position absolute
      width $nav-btn-width
      height $nav-btn-height
      background $main
      border-radius 3px
    
    &:before
      top -1 * $bar-offset
    
    &:after
      bottom -1 * $bar-offset
  .month
    color $main
    padding-left 25px
    
  .header-right-wrapper
    display flex
    flex-grow 1
    align-items center
    justify-content flex-end
    height 100%
    
    .menu-btn
      $dot-offset = $menu-btn-size + 2px
      position relative
      width $menu-btn-size
      height $menu-btn-size
      background $main
      margin-top -1px // again...
      border-radius 50%
      
      &:before
      &:after
        content ''
        display block
        position absolute
        width $menu-btn-size
        height $menu-btn-size
        background $main
        border-radius 50%
        
      &:before
        top -1 * $dot-offset
        
      &:after
        bottom -1 * $dot-offset
        
.app-calendar
  padding 0 ($app-gutter-size / 2)
  padding-bottom $app-gutter-size
  
  .calendar-row
    display flex
    align-items center
    justify-content space-between
    
    &:not(:first-of-type)
      margin-top 4px
    
    .day
      display inline-flex
      align-items center
      justify-content center
      width $calendar-day-size
      height $calendar-day-size
      font-size 12px
      padding $calendar-day-padding
      color $day-text
      border-radius 50%
      cursor pointer
      user-select none
      
      &.day-name
        color $faded-text
        
      &.event
        position relative
        color white
        
        &:before
          content ''
          display block
          position absolute
          
          top 0
          left 0
          
          width $calendar-day-size + ($calendar-day-padding / 2)
          height @width
          border-radius 50%
          z-index -1
          transition transform .25s ease-in-out
        
        &.blue
          background $day-blue
          &:before
            background $day-blue
          
        &.purple
          background $day-purple
          &:before
            background $day-purple
          
        &.pink
          background $day-pink
          &:before
            background $day-pink
            
        &.animate
          position static
          
          &:before
            // Just below the end of the large day header
            top ($app-day-header-large - ($calendar-day-size * 2))
            left 55px
            z-index 1
            will-change transform
          
.app-divider
  height 1px
  background darken(white, 7%)
  
.app-events
  padding 0 $app-gutter-size
  
  .app-event
    display flex
    align-items center
    justify-content flex-start
    margin-top $app-gutter-size
    
    .event-date
      display inline-flex
      align-items center
      justify-content center
      width 40px
      height 40px
      border-radius 50%
      color white
      
      &.blue
        background $day-blue
        
      &.purple
        background $day-purple
        
      &.pink
        background $day-pink
        
    .event-title
      color $day-text
      padding-left 16px
      
.app-day-container
  position absolute
  top 0
  left 0
  width 100%
  height 100%
  border-radius 3px
  
  opacity 1
  transform translate(0, 0)
  z-index 1
  overflow hidden
  
  &.animate-out
    animation day-container-out .15s ease-out forwards
    will-change transform
  
  &.hidden
    z-index -100
    
  .day-header
    position relative
    top 0
    left 0
    display flex
    flex-direction column
    height $app-header-height
    padding $app-gutter-size
    overflow hidden
    z-index 2
    transition height .075s linear
    
    &.day-header--large
      height $app-day-header-large
      
      .day-header-content
        font-weight lighter
        padding $app-gutter-size
        height $app-day-header-large
        padding-top $app-header-height
        
        .day-header-title
          .day-header-title-day
            font-size 54px
            
          .day-header-title-month
            font-size 28px
          
        .day-header-event
          font-size 24px
          padding-top $app-gutter-size
  
    .day-header-bg
      position absolute
      top $app-day-header-large - $calendar-day-size - $calendar-day-padding
      left 55px
      width $calendar-day-size + ($calendar-day-padding / 2)
      height @width
      border-radius 50%
      will-change transform
      transform scale(1)
      
      &.pink
        background $day-pink
        
      &.purple
        background $day-purple
        
      &.blue
        background $day-blue
  
      &.animate
        animation day-header-grow .25s .05s ease-in-out forwards
  
    .day-header-close
      position absolute
      top ($app-gutter-size - $app-close-btn-thickness)
      right ($app-gutter-size - $app-close-btn-thickness)
      width $app-close-btn-size
      height $app-close-btn-size
      opacity 0
      cursor pointer
      transition opacity .15s ease-out
      z-index 4
      
      &:before
      &:after
        content ''
        display block
        position absolute
        top 50%
        left 50%
        width 100%
        height $app-close-btn-thickness
        background white
        border-radius 3px
        transform-origin center center
      
      &:before
        transform translate(-50%, -50%) rotate(45deg)
      &:after
        transform translate(-50%, -50%) rotate(-45deg)
  
      &.animate
        opacity 1
        
    .day-header-content
      position absolute
      display flex
      flex-direction column
      padding ($app-gutter-size / 2)
      top 0
      left 0
      width 100%
      height $app-day-header-height
      color white
      z-index 3
      opacity 0
      transform translateY(18px)
      
      &.animate-in
        animation day-header-content-in .15s ease-out forwards
      
      .day-header-title
        font-weight normal
        
        .day-header-title-day
        .day-header-title-month
          display inline
          vertical-align baseline
          
        .day-header-title-day
          font-size 18px
          
        .day-header-title-month
          font-size 18px
          
      .day-header-event
        padding-top 2px
        font-size 12px
        font-weight normal
  
  .day-content
    position absolute
    top 0
    left 0
    width 100%
    height 100%
    overflow-y auto
    z-index 0
    opacity 0
    padding-top $app-day-header-large + $app-gutter-size
    padding-left $app-gutter-size
    padding-right $app-gutter-size
    transform translateY(35px)
    background white
    
    &.animate-in
      animation day-content-animate-in .2s ease-out forwards
        
    .img
      margin-top $app-gutter-size
      margin-bottom $app-gutter-size
      width 100%
      height 150px
      background $main
      
@keyframes day-header-grow
  0%
    transform scale(1)
  100%
    transform scale(25)
    
@keyframes day-container-out
  0%
    transform translateY(0)
    opacity 1
  100%
    transform translateY(45px)
    opacity 0
    
@keyframes day-header-content-in
  0%
    transform translateY(18px)
    opacity 0
  100%
    transform translateY(0)
    opacity 1
    
@keyframes day-content-animate-in
  0%
    transform translateY(35px)
    opacity 0
  100%
    transform translateY(0)
    opacity 1
            
          
!
            
              const style = document.createElement('style')
document.head.appendChild(style)

const headerDot = document.querySelector('.day-header-bg')
const headerDotClasses = ['pink', 'purple', 'blue']

const headerCloseBtn = document.querySelector('.day-header-close')

const dayContainer = document.querySelector('.app-day-container')
const dayHeaderTitleDay = document.querySelector('.day-header-title-day')
const dayHeaderContent = document.querySelector('.day-header-content')
const dayHeaderEvent = document.querySelector('.day-header-event')
const dayContent = document.querySelector('.day-content')
const dayHeader = document.querySelector('.day-header')

dayContent.addEventListener('scroll', _ => {
  if (_.target.scrollTop > 155) {
    if (dayHeader.classList.contains('day-header--large')) {
      dayHeader.classList.remove('day-header--large')
      dayHeader.classList.add('sticky')
      dayHeader.style.height = `${46}px`
    }
  } else if (_.target.scrollTop < 155) {
    if (!dayHeader.classList.contains('day-header--large')) {
      dayHeader.classList.add('day-header--large')
      dayHeader.classList.remove('sticky')
      dayHeader.style.height = `${200}px`
    }
    dayHeader.style.height = `${200 - _.target.scrollTop}px`
  }
})

headerCloseBtn.addEventListener('click', _ => {
  dayContainer.classList.add('animate-out')
  
  setTimeout(() => {
    dayContainer.classList.add('hidden')
    dayContainer.classList.remove('animate-out')
    dayHeaderContent.classList.remove('animate-in')
    dayContent.classList.remove('animate-in')
    dayHeader.classList.add('day-header--large')
    dayHeader.classList.remove('sticky')
    dayContent.scrollTop = 0
    headerCloseBtn.classList.remove('animate')
    headerDot.classList.remove('animate')
      headerDotClasses.forEach(c => {
      headerDot.classList.remove(c)
    })
    style.innerHTML = ''
  }, 155)
})

Array.from(document.querySelectorAll('[data-day]'))
  .forEach(day => {
    const selector = 
          `.app .app-calendar .calendar-row .day.event[data-day="${day.dataset.day}"]:before`
    const colorClass = headerDotClasses.filter(c => {
      return day.classList.contains(c)
    })[0]
    
    
    day.addEventListener('click', _ => {
      const animate = _.target.classList.contains('animate')
      dayContainer.classList.remove('hidden')
      headerDot.classList.remove('animate')
      headerDotClasses.forEach(c => {
        headerDot.classList.remove(c)
      })
      
      dayHeaderTitleDay.innerText = day.dataset.day
      dayHeaderEvent.innerText = day.dataset.event
      
      if (!animate) {
        style.innerHTML = 
          `${selector} {
            top: ${_.target.offsetTop}px;
            left: ${_.target.offsetLeft}px;
          }`
      } else {
        style.innerHTML = ''
      }
      _.target.classList.add('animate')
      
      // Just above the bottom of the header
      // Math done from the vars in the stylus
      const endPos = { x: 55, y: 166 }
      
      style.innerHTML = 
        `${selector} {
            top: ${_.target.offsetTop}px;
            left: ${_.target.offsetLeft}px;
          }
         ${selector} {
            transform: translate(
              ${String(endPos.x - _.target.offsetLeft) + 'px'},
              ${String(endPos.y - _.target.offsetTop) + 'px'}
            )
        }`
      
      setTimeout(() => {
        _.target.classList.remove('animate')
        headerDot.classList.add(colorClass)
        headerDot.classList.add('animate')
        dayContent.classList.add('animate-in')
        
        setTimeout(() => {
          headerCloseBtn.classList.add('animate')
          dayHeaderContent.classList.add('animate-in')
        }, 150)
      }, 150)
    })
})
            
          
!
999px
🕑 One or more of the npm packages you are using needs to be built. You're the first person to ever need it! We're building it right now and your preview will start updating again when it's ready.

Console