소스 검색

Merge branch 'Transitions-with-CSS-animation'

* Transitions-with-CSS-animation:
  First steps for tablet routering
  Aside/router functionality
  Aside animations
  Refactors and CSS fixes
  Changes to support android 2.2 and refactors
  Fade animation included and prevent routering if something is
animating
  Firsts test with new animations
  First tests with animation keyframes
  Better fix on Lungo.Router
  Fixed history on Lungo.Router

Conflicts:
	example/navigation.html
	src/stylesheets/__init.styl
	src/stylesheets/lungo.layout.styl
	src/stylesheets/lungo.media.tablet.styl
piniphone 13 년 전
부모
커밋
a2b84ff3e4

+ 6 - 2
GruntFile.coffee

@@ -32,7 +32,9 @@ module.exports = (grunt) ->
         'src/modules/Lungo.Resource.coffee',
         'src/modules/Lungo.Scroll.coffee',
         'src/modules/Lungo.Service.coffee',
-        'src/modules/Lungo.Router.coffee',
+        # 'src/modules/Lungo.Router.coffee',
+        'src/modules/Lungo.Router.Phone.coffee',
+        'src/modules/Lungo.Router.Tablet.coffee',
         'src/modules/Lungo.Aside.coffee',
         'src/modules/Lungo.Section.coffee',
         'src/modules/Lungo.Article.coffee',
@@ -44,7 +46,9 @@ module.exports = (grunt) ->
         'src/stylesheets/lungo.layout.*.styl',
         'src/stylesheets/lungo.widget.styl',
         'src/stylesheets/lungo.widget.*.styl',
-        'src/stylesheets/lungo.media.*.styl']
+        'src/stylesheets/lungo.media.*.styl',
+        'src/stylesheets/lungo.animation.styl',
+        'src/stylesheets/lungo.animation.*.styl']
       theme: [
         'src/stylesheets/theme/theme.*.styl']
       theme_firefoxos: [

+ 127 - 0
example/navigation.tablet.html

@@ -0,0 +1,127 @@
+<!doctype html>
+<html>
+<head>
+    <meta charset="utf-8">
+    <title>Lungo Flexbox - SDK</title>
+    <meta name="description" content="">
+    <meta name="author" content="Javier Jiménez Villar (@soyjavi)">
+    <meta name="HandheldFriendly" content="True">
+    <meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
+    <meta name="apple-mobile-web-app-capable" content="yes">
+    <meta name="apple-mobile-web-app-status-bar-style" content="black">
+    <meta name="format-detection" content="telephone=no">
+    <meta http-equiv="cleartype" content="on">
+
+    <!-- Main Stylesheet -->
+    <link rel="stylesheet" href="components/lungo.brownie/lungo.css">
+    <link rel="stylesheet" href="components/lungo.brownie/lungo.theme.css">
+    <link rel="stylesheet" href="components/lungo.icon/lungo.icon.css">
+
+</head>
+
+<body>
+
+    <aside id="menu" data-transition="left">
+        <header data-title="My mailbox"></header>
+        <article id="menu_article" class="active list scroll">
+            <ul>
+                <li data-view-article="incoming">Incoming</li>
+                <li data-view-article="later">Later</li>
+                <li data-view-article="lists">Lists</li>
+                <li data-view-article="archived">Archived</li>
+                <li data-view-section="clean">clean</li>
+            </ul>
+        </article>
+    </aside>
+
+    <!-- ===================================================================================== -->
+    <!-- ===================================================================================== -->
+
+    <section id="incoming" data-transition="slide" data-children="mail" data-aside="menu">
+        <header data-title="Mail">
+            <nav class="left">
+                <button data-icon="list" data-view-aside="menu"></button>
+            </nav>
+            <nav class="right">
+            </nav>
+        </header>
+        <article id="incoming" class="list scroll">
+            <ul>
+                <li data-view-section="mail2" class="text bold">Cirque du soleil</li>
+                <li data-view-section="mail" class="text bold">Twitter</li>
+            </ul>
+        </article>
+        <article id="later" class="list scroll">
+            <ul>
+                <li data-view-section="mail2" class="text bold">Later cirque du soleil</li>
+                <li data-view-section="mail" class="text bold">Later twitter</li>
+            </ul>
+        </article>
+        <article id="lists" class="list scroll">
+            <ul>
+                <li data-view-section="mail2" class="text bold">Lists cirque du soleil</li>
+                <li data-view-section="mail" class="text bold">Lists twitter</li>
+            </ul>
+        </article>
+        <article id="archived" class="list scroll">
+            <ul>
+                <li data-view-section="mail2" class="text bold">Archived cirque du soleil</li>
+                <li data-view-section="mail" class="text bold">Archived twitter</li>
+            </ul>
+        </article>
+        <footer>
+            <nav>
+                <a href="#" data-view-article="incoming">incoming</a>
+                <a href="#" data-view-article="later">later</a>
+                <a href="#" data-view-article="lists">lists</a>
+                <a href="#" data-view-article="archived">archived</a>
+                <a href="#" data-view-article="main_article_1">main_article_1</a>
+            </nav>
+        </footer>
+    </section>
+
+    <!-- ===================================================================================== -->
+    <!-- ===================================================================================== -->
+
+    <section id="mail" data-transition="slide">
+        <header data-title="Mail 1" data-back="home">
+            <nav class="right">
+                <button data-article="article_2" data-view-article="article_1" data-label="Article 1"></button>
+                <button data-article="article_1" data-view-article="article_2" data-label="Article 2"></button>
+            </nav>
+        </header>
+        <article id="article_1" class="scroll indented text big">Article 1</article>
+        <article id="article_2" class="scroll indented text big">Article 2</article>
+    </section>
+    <section id="mail2" data-transition="slide">
+        <header data-title="Mail 2" data-back="home">
+            <nav class="right">
+                <button data-article="mail_article_2" data-view-article="main_article_1" data-label="Article 1"></button>
+                <button data-article="main_article_1" data-view-article="mail_article_2" data-label="Article 2"></button>
+            </nav>
+        </header>
+        <article id="main_article_1" class="scroll indented text big">Article Mail2 1</article>
+        <article id="mail_article_2" class="scroll indented text big">Article Mail2 2</article>
+    </section>
+
+    <!-- ===================================================================================== -->
+    <!-- ===================================================================================== -->
+
+    <section id="clean" data-transition="slide">
+        <header data-title="Clean" data-back="home"></header>
+        <article id="clean_1" class="scroll indented text big">Clean!</article>
+    </section>
+
+
+    <script src="components/quojs/quo.js"></script>
+    <script src="components/lungo.brownie/lungo.debug.js"></script>
+    <script>
+        Lungo.init({
+            name: 'Flexbox',
+            version: '2.2',
+            history: true
+        });
+        $$("[data-router=back]").tap(function(event) { Lungo.Router.back();});
+    </script>
+</body>
+</html>

+ 2 - 2
example/test.html

@@ -46,7 +46,7 @@
 
         <nav data-control="groupbar" data-os="android" data-article="folks">
             <a href="#" data-view-article="folks" data-label="Folks" data-count="11"></a>
-            <a href="#" data-view-article="products" data-async="static/articles/products.html" data-label="Products" id="products"></a>
+            <a href="#" data-view-article="products" data-async="static/articles/products.html" data-label="Products" ></a>
         </nav>
 
         <article id="folks" class="active list scroll indente-d">
@@ -110,7 +110,7 @@
         <footer data-os="ios">
             <nav>
                 <a href="#" data-view-article="folks" data-icon="desktop" data-count="11"></a>
-                <a href="#" data-view-article="products" data-icon="tablet" data-count="5"></a>
+                <a href="#" data-view-article="products" data-async="static/articles/products.html" data-icon="tablet" data-count="5"></a>
             </nav>
         </footer>
     </section>

+ 21 - 5
src/boot/Lungo.Boot.Events.coffee

@@ -6,9 +6,11 @@ Initialize the automatic DOM UI events
 
 @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
 @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
+@author Ignacio Olalde <ina@tapquo.com> || @piniphone
 ###
 
-Lungo.Boot.Events = do(lng = Lungo) ->
+Lungo.Boot.Events = do (lng = Lungo) ->
+
   C = lng.Constants
   ATTRIBUTE = lng.Constants.ATTRIBUTE
   CLASS = lng.Constants.CLASS
@@ -28,7 +30,10 @@ Lungo.Boot.Events = do(lng = Lungo) ->
     lng.dom(C.QUERY.ASIDE_ROUTER).touch _onAside
     lng.dom(C.QUERY.MENU_ROUTER).touch _onMenu
     lng.dom(QUERY.MENU_HREF).touch _closeMenu
-    lng.dom(QUERY.CONTROL_CHECKBOX).on "change", _changeCheckboxValue
+    lng.dom(QUERY.CONTROL_CHECKBOX).on C.EVENT.CHANGE, _changeCheckboxValue
+    for transition in C.EVENT.TRANSITION_END
+      lng.dom(C.ELEMENT.SECTION).on transition, _transitionEnd
+      lng.dom(C.ELEMENT.ASIDE).on transition, _transitionEnd
 
   _onSection = (event) ->
     event.preventDefault()
@@ -46,7 +51,7 @@ Lungo.Boot.Events = do(lng = Lungo) ->
       _onAsyncResource el, C.ELEMENT.ARTICLE
     else
       lng.Router.article lng.Router.history(), el.data("view-article"), el
-      lng.Aside.hide()
+      # lng.Aside.hide()
 
   _onAsyncResource = (el, type) ->
     url = el.data "async"
@@ -70,8 +75,9 @@ Lungo.Boot.Events = do(lng = Lungo) ->
 
 
   _onAside = (event) ->
-    event.preventDefault()
-    lng.Aside.toggle()
+    do event.preventDefault
+    aside_id = lng.dom(event.target).closest(C.QUERY.ASIDE_ROUTER).data "view-aside"
+    lng.Aside.toggle aside_id
 
   _onMenu = (event) ->
     event.preventDefault()
@@ -85,6 +91,7 @@ Lungo.Boot.Events = do(lng = Lungo) ->
     lng.dom("[data-view-menu=#{parent}] > .icon").attr "class", "icon " + el.data("icon")
 
   _changeCheckboxValue = (event) ->
+    #@TODO >> Refactor names
     event.preventDefault()
     el = lng.dom(this)
     input = el.find "input"
@@ -93,4 +100,13 @@ Lungo.Boot.Events = do(lng = Lungo) ->
     el.removeClass "checked"
     if checked  then el.addClass "checked"
 
+  _transitionEnd = (event) ->
+    section = lng.dom(event.target)
+    asideRelated = section.hasClass("asideHidding") or section.hasClass("asideShowing")
+    shadowRelated = section.hasClass("shadowing") or section.hasClass("unshadowing")
+
+    if section.data("direction") or asideRelated or shadowRelated then lng.Router.animationEnd event
+    else lng.Aside.animationEnd event
+
+
   init: init

+ 48 - 43
src/modules/Lungo.Aside.coffee

@@ -7,66 +7,71 @@ Initialize the <articles> layout of a certain <section>
 @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
 ###
 
-Lungo.Aside = do(lng = Lungo) ->
+Lungo.Aside = do (lng = Lungo) ->
+
   C = lng.Constants
+  _callback = undefined
 
   ###
-  Active aside for a determinate section
-  @method active
-  @param  {object} Section element
+  Display an aside element with a particular <section>
+  @method show
   ###
-  active = (section) ->
-    aside_id = section.data("aside")
-    current_aside = lng.Element.Cache.aside
-
-    # Deactive
-    if current_aside and aside_id isnt current_aside?.attr(C.ATTRIBUTE.ID)
+  show = (aside_id, animate_section = true) ->
+    aside = lng.dom("##{aside_id}")
+    if aside.length
+      lng.Element.Cache.aside = aside
+      aside_transition = aside.data(C.TRANSITION.ATTR) or "left"
+      aside.addClass(C.CLASS.SHOW)
       if lng.DEVICE is C.DEVICE.PHONE
-        current_aside.removeClass(C.CLASS.SHOW).removeClass C.CLASS.ACTIVE
+        lng.Element.Cache.section.data("aside-#{aside_transition}", "show")
       else
-        current_aside.addClass(C.CLASS.HIDE)
-        setTimeout (-> current_aside.removeClass(C.CLASS.SHOW).removeClass(C.CLASS.ACTIVE).removeClass(C.CLASS.HIDE)), C.TRANSITION.DURATION
-      lng.Element.Cache.aside = null
-
-    # Active
-    if aside_id
-      lng.Element.Cache.aside = lng.dom(C.ELEMENT.ASIDE + "#" + aside_id)
-      lng.Element.Cache.aside.addClass C.CLASS.ACTIVE
-      lng.Aside.show aside_id  unless lng.DEVICE is C.DEVICE.PHONE
-    lng.Element.Cache.aside
+        aside_section = lng.dom("[data-aside=#{aside_id}]")
+        if aside_section.attr("id") isnt lng.Element.Cache.section.attr("id")
+          lng.Element.Cache.section.addClass "shadowing"
+        aside_section.removeClass("aside").addClass "asideShowing"
 
+  ###
+  Hide an aside element with a particular section
+  @method hide
+  ###
+  hide = (callback) ->
+    if lng.Element.Cache.aside
+      _callback = callback
+      aside_transition = lng.Element.Cache.aside.data(C.TRANSITION.ATTR) or "left"
+      if lng.DEVICE is C.DEVICE.PHONE
+        lng.Element.Cache.section.data("aside-#{aside_transition}", "hide")
+      else
+        lng.dom(".aside").removeClass("aside").addClass("asideHidding")
+        lng.Element.Cache.aside = null
+        if callback then callback.call callback
+        lng.dom(".shadow").removeClass("shadow").addClass("unshadowing")
+    else if callback then callback.call callback
 
   ###
   Toggle an aside element
   @method toggle
   @param  {string} Aside id
   ###
-  toggle = ->
-    if lng.Element.Cache.aside
-      is_visible = lng.Element.Cache.aside.hasClass(C.CLASS.SHOW)
-      if is_visible then lng.Aside.hide() else lng.Aside.show()
+  toggle = (aside) ->
+    if lng.Element.Cache.aside then do lng.Aside.hide
+    else lng.Aside.show aside
 
 
   ###
-  Display an aside element with a particular <section>
-  @method show
+  Triggered when <aside> animation ends.
+  @method   animationEnd
+  @param    {object} event
   ###
-  show = ->
-    if lng.Element.Cache.aside?
-      setTimeout (-> lng.Element.Cache.aside.addClass C.CLASS.SHOW), C.TRANSITION.DURATION
-      if lng.DEVICE is C.DEVICE.PHONE
-        lng.Element.Cache.aside.addClass C.CLASS.SHOW
-        lng.Element.Cache.section.addClass(_asideStylesheet()).addClass(C.CLASS.ASIDE)
-
+  animationEnd = (event) ->
+    section = lng.dom(event.target)
+    aside_transition = lng.Element.Cache.aside.data(C.TRANSITION.ATTR) or "left"
+    if section.data("aside-#{aside_transition}") is "hide"
+      lng.Element.Cache.aside.removeClass(C.CLASS.SHOW)
+      lng.Element.Cache.aside = null
+      section.removeAttr("data-aside-#{aside_transition}")
+      if _callback then _callback.call _callback
+      _callback = undefined
 
-  ###
-  Hide an aside element with a particular section
-  @method hide
-  ###
-  hide = ->
-    if lng.Element.Cache.aside? and lng.DEVICE is C.DEVICE.PHONE
-      lng.Element.Cache.section.removeClass(C.CLASS.ASIDE)
-      setTimeout (-> lng.Element.Cache.aside.removeClass C.CLASS.SHOW), C.TRANSITION.DURATION
 
   ###
   @todo
@@ -110,8 +115,8 @@ Lungo.Aside = do(lng = Lungo) ->
   _asideStylesheet = ->
     if lng.Element.Cache.aside?.hasClass(C.CLASS.RIGHT) then "#{C.CLASS.RIGHT}" else "  "
 
-  active: active
   toggle: toggle
   show: show
   hide: hide
   draggable: draggable
+  animationEnd: animationEnd

+ 74 - 67
src/modules/Lungo.Constants.coffee

@@ -9,87 +9,94 @@ Object with data-attributes (HTML5) with a special <markup>
 
 Lungo.Constants =
   ELEMENT:
-    SECTION             : "section"
-    ARTICLE             : "article"
-    ASIDE               : "aside"
-    MENU                : "menu"
-    BODY                : "body"
-    DIV                 : "div"
-    LIST                : "<ul></ul>"
-    LI                  : "li"
+    SECTION              : "section"
+    ARTICLE              : "article"
+    ASIDE                : "aside"
+    MENU                 : "menu"
+    BODY                 : "body"
+    DIV                  : "div"
+    LIST                 : "<ul></ul>"
+    LI                   : "li"
 
   QUERY:
-    ARTICLE_ROUTER      : "[data-view-article]"
-    SECTION_ROUTER      : "[data-view-section]"
-    ARTICLE_ROUTER_TOUCH: "header [data-view-article], footer [data-view-article], nav[data-control] [data-view-article]"
-    SECTION_ROUTER_TOUCH: "header [data-view-section], footer [data-view-section], nav[data-control] [data-view-section]"
-    ARTICLE_ROUTER_TAP  : "article [data-view-article]"
-    SECTION_ROUTER_TAP  : "article [data-view-section]"
-    ASIDE_ROUTER        : "[data-view-aside]"
-    MENU_ROUTER         : "[data-view-menu]"
+    ARTICLE_ROUTER       : "[data-view-article]"
+    SECTION_ROUTER       : "[data-view-section]"
+    ARTICLE_ROUTER_TOUCH : "header [data-view-article], footer [data-view-article], nav[data-control] [data-view-article]"
+    SECTION_ROUTER_TOUCH : "header [data-view-section], footer [data-view-section], nav[data-control] [data-view-section]"
+    ARTICLE_ROUTER_TAP   : "article [data-view-article]"
+    SECTION_ROUTER_TAP   : "article [data-view-section]"
+    ASIDE_ROUTER         : "[data-view-aside]"
+    MENU_ROUTER          : "[data-view-menu]"
 
-    LIST_IN_ELEMENT     : "article.list"
-    ELEMENT_SCROLLABLE  : "article.scroll"
-    HREF_ASIDE          : "section[data-aside].drag"
-    HREF_ROUTER         : "a[href][data-router]"
-    MENU_HREF           : "[data-control=menu] a[href]"
-    CONTROL_CHECKBOX    : "[data-control-checkbox]"
-    NAVIGATION_ITEM     : "a[href][data-router=\"article\"]"
-    ARTICLE_REFERENCE   : "[data-article]"
-    TITLE               : "header .title, footer .title"
-    ACTIVE_LIST_ITEM    : "li a.active, li.active"
+    LIST_IN_ELEMENT      : "article.list"
+    ELEMENT_SCROLLABLE   : "article.scroll"
+    HREF_ASIDE           : "section[data-aside].drag"
+    HREF_ROUTER          : "a[href][data-router]"
+    MENU_HREF            : "[data-control=menu] a[href]"
+    CONTROL_CHECKBOX     : "[data-control-checkbox]"
+    NAVIGATION_ITEM      : "a[href][data-router=\"article\"]"
+    ARTICLE_REFERENCE    : "[data-article]"
+    TITLE                : "header .title, footer .title"
+    ACTIVE_LIST_ITEM     : "li a.active, li.active"
 
   CLASS:
-    ACTIVE              : "active"
-    ASIDE               : "aside"
-    SHOW                : "show"
-    HIDE                : "hide"
-    HIDING              : "hiding"
-    RIGHT               : "right"
-    LEFT                : "left"
-    HORIZONTAL          : "horizontal"
-    SMALL               : "small"
-    LAST                : "last"
+    ACTIVE               : "active"
+    ASIDE                : "aside"
+    SHOW                 : "show"
+    HIDE                 : "hide"
+    HIDING               : "hiding"
+    RIGHT                : "right"
+    LEFT                 : "left"
+    HORIZONTAL           : "horizontal"
+    SMALL                : "small"
+    LAST                 : "last"
 
   TRIGGER:
-    LOAD                : "load"
-    UNLOAD              : "unload"
+    LOAD                 : "load"
+    UNLOAD               : "unload"
+
+  EVENT:
+    TRANSITION_END       : ["webkitAnimationEnd", "animationend"]
+    CHANGE               : "change"
 
   TRANSITION:
-    DURATION            : 400
-    ORIGIN              : "transition-origin"
-    ATTR                : "transition"
+    DURATION             : 400
+    ORIGIN               : "transition-origin"
+    ATTR                 : "transition"
 
   ATTRIBUTE:
-    ID                  : "id"
-    HREF                : "href"
-    TITLE               : "title"
-    ARTICLE             : "article"
-    CLASS               : "class"
-    WIDTH               : "width"
-    HEIGHT              : "height"
-    PIXEL               : "px"
-    PERCENT             : "%"
-    ROUTER              : "router"
-    FIRST               : "first"
-    LAST                : "last"
-    EMPTY               : ""
-    CHILDREN            : "children"
-    TRANSITION          : "transition"
+    ID                   : "id"
+    HREF                 : "href"
+    TITLE                : "title"
+    ARTICLE              : "article"
+    CLASS                : "class"
+    WIDTH                : "width"
+    HEIGHT               : "height"
+    PIXEL                : "px"
+    PERCENT              : "%"
+    ROUTER               : "router"
+    FIRST                : "first"
+    LAST                 : "last"
+    EMPTY                : ""
+    CHILDREN             : "children"
+    TRANSITION           : "transition"
+    STATE                : "state"
+    DIRECTION            : "direction"
 
   BINDING:
-    START               : "{{"
-    END                 : "}}"
-    KEY                 : "value"
-    SELECTOR            : "{{value}}"
+    START                : "{{"
+    END                  : "}}"
+    KEY                  : "value"
+    SELECTOR             : "{{value}}"
 
   DEVICE:
-    PHONE               : "phone"
-    TABLET              : "tablet"
-    TV                  : "tv"
+    PHONE                : "phone"
+    TABLET               : "tablet"
+    TV                   : "tv"
 
   ERROR:
-    DATABASE            : "ERROR: Connecting to Data.Sql."
-    DATABASE_TRANSACTION: "ERROR: Data.Sql >> "
-    ROUTER              : "ERROR: The target does not exists >>"
-    LOADING_RESOURCE    : "ERROR: Loading resource: "
+    DATABASE             : "ERROR: Connecting to Data.Sql."
+    DATABASE_TRANSACTION : "ERROR: Data.Sql >> "
+    ROUTER               : "ERROR: The target does not exists >>"
+    LOADING_RESOURCE     : "ERROR: Loading resource: "
+

+ 2 - 0
src/modules/Lungo.Init.coffee

@@ -10,6 +10,8 @@ Lungo.init = (config) ->
   Lungo.Config = config
   Lungo.Resource.load config.resources if config and config.resources
   do Lungo.Boot.Device.init
+  isPhone = Lungo.DEVICE is Lungo.Constants.DEVICE.PHONE
+  Lungo.Router = if isPhone then Lungo.RouterPhone else Lungo.RouterTablet
   do Lungo.Boot.Events.init
   do Lungo.Boot.Data.init
   do Lungo.Boot.Layout.init

+ 59 - 37
src/modules/Lungo.Router.coffee

@@ -6,13 +6,16 @@ Handles the <sections> and <articles> to show
 
 @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
 @author Guillermo Pascual <pasku@tapquo.com> || @pasku1
+@author Ignacio Olalde <ina@tapquo.com> || @piniphone
 ###
 
-Lungo.Router = do(lng = Lungo) ->
-  C        = lng.Constants
-  HASHTAG  = "#"
-  _history = []
 
+Lungo.RouterPhone = do (lng = Lungo) ->
+
+  C                   = lng.Constants
+  HASHTAG             = "#"
+  _history            = []
+  _animating          = false
 
   ###
   Navigate to a <section>.
@@ -20,44 +23,32 @@ Lungo.Router = do(lng = Lungo) ->
   @param    {string} Id of the <section>
   ###
   section = (section_id) ->
+    return false if _animating
     current = lng.Element.Cache.section
-    if _notCurrentTarget(current, section_id)
+    if _notCurrentTarget current, section_id
       query = C.ELEMENT.SECTION + HASHTAG + section_id
-      target = if current then current.siblings(query) else lng.dom(query)
-      if target.length > 0
-        if lng.DEVICE is C.DEVICE.PHONE and current?
-          current.siblings("#{C.ELEMENT.SECTION}.#{C.CLASS.LAST}").removeClass C.CLASS.LAST
-          lng.Section.defineTransition target, current
-          current.removeClass(C.CLASS.SHOW).addClass(C.CLASS.HIDE).addClass(C.CLASS.LAST)
-
-        lng.Section.show current, target
+      future = if current then current.siblings(query) else lng.dom(query)
+      if future.length
+        _section future, current
         lng.Router.step section_id
-        do _url if Lungo.Config.history
+        do _url unless Lungo.Config.history is false
         do _updateNavigationElements
-
+    else if lng.Element.Cache.aside then do lng.Aside.hide
 
   ###
   Return to previous section.
   @method   back
   ###
   back = ->
-    _removeLast()
+    return false if _animating
+    do _removeLast
     current = lng.Element.Cache.section
     query = C.ELEMENT.SECTION + HASHTAG + history()
-    target = current.siblings(query)
-    if lng.DEVICE is C.DEVICE.PHONE
-      lng.Aside.hide()
-      lng.Section.assignTransition target, target.data C.TRANSITION.ORIGIN
-      current.removeClass(C.CLASS.SHOW).addClass(C.CLASS.HIDING)
-      setTimeout (->
-        current.removeClass(C.CLASS.HIDING)
-      ), C.TRANSITION.DURATION
-      if target.hasClass("aside") then lng.Aside.toggle()
-
-    lng.Section.show current, target
-    do _url if Lungo.Config.history?
-    do _updateNavigationElements
-
+    future = current.siblings(query)
+    if future.length
+      _section future, current, true
+      do _url unless Lungo.Config.history is false
+      do _updateNavigationElements
 
   ###
   Displays the <article> in a particular <section>.
@@ -75,9 +66,20 @@ Lungo.Router = do(lng = Lungo) ->
 
         if element?.data(C.ATTRIBUTE.TITLE)?
           lng.Element.Cache.section.find(C.QUERY.TITLE).text element.data(C.ATTRIBUTE.TITLE)
-        do _url if Lungo.Config.history
+        do _url unless Lungo.Config.history is false
         do _updateNavigationElements
 
+  ###
+  Triggered when <section> animation ends. Reset animation classes of section and aside
+  @method   animationEnd
+  @param    {eventObject}
+  ###
+  animationEnd = (event) ->
+    section = lng.dom(event.target)
+    direction = section.data(C.ATTRIBUTE.DIRECTION)
+    section.removeClass C.CLASS.SHOW if direction is "out" or direction is "back-out"
+    section.removeAttr "data-#{C.ATTRIBUTE.DIRECTION}"
+    _animating = false
 
   ###
   Create a new element to the browsing history based on the current section id.
@@ -93,10 +95,27 @@ Lungo.Router = do(lng = Lungo) ->
   ###
   history = -> _history[_history.length - 1]
 
-
   ###
   Private methods
   ###
+  _section = (future, current, backward = false) ->
+    callback = -> _show future, current, backward
+    if lng.Element.Cache.aside then lng.Aside.hide callback
+    else do callback
+
+  _show = (future, current, backward) ->
+    if current? then _setSectionDirections future, current, backward
+    lng.Section.show current, future
+
+  _setSectionDirections = (future, current, backward=false) ->
+    if not current? or not future.length then return false
+    _animating = true
+    dirPrefix = if backward then "back-" else ""
+    future.addClass(C.CLASS.SHOW)
+    future.data(C.ATTRIBUTE.DIRECTION, "#{dirPrefix}in") if future.data(C.TRANSITION.ATTR)
+    if current.data(C.TRANSITION.ATTR) then current.data(C.ATTRIBUTE.DIRECTION, "#{dirPrefix}out")
+    else current.removeClass(C.CLASS.SHOW)
+
   _notCurrentTarget = (current, id) -> current?.attr(C.ATTRIBUTE.ID) isnt id
 
   _url = ->
@@ -107,17 +126,20 @@ Lungo.Router = do(lng = Lungo) ->
 
   _updateNavigationElements = ->
     article_id = lng.Element.Cache.article.attr C.ATTRIBUTE.ID
-
-    lng.dom(C.QUERY.ARTICLE_ROUTER).removeClass(C.CLASS.ACTIVE).filter("[data-view-article=#{article_id}]").addClass(C.CLASS.ACTIVE)
-
+    # Active visual signal for elements
+    links = lng.dom(C.QUERY.ARTICLE_ROUTER).removeClass(C.CLASS.ACTIVE)
+    links.filter("[data-view-article=#{article_id}]").addClass(C.CLASS.ACTIVE)
+    # Hide/Show elements in current article
     nav = lng.Element.Cache.section.find(C.QUERY.ARTICLE_REFERENCE).addClass C.CLASS.HIDE
     nav.filter("[data-article*='#{article_id}']").removeClass C.CLASS.HIDE
 
-  _removeLast = -> _history.length -= 1
-
+  _removeLast = ->
+    if _history.length > 1
+      _history.length -= 1
 
   section : section
   back    : back
   article : article
   history : history
   step    : step
+  animationEnd : animationEnd

+ 170 - 0
src/modules/Lungo.Router.Tablet.coffee

@@ -0,0 +1,170 @@
+###
+Handles the <sections> and <articles> to show
+
+@namespace Lungo
+@class Router
+
+@author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
+@author Guillermo Pascual <pasku@tapquo.com> || @pasku1
+@author Ignacio Olalde <ina@tapquo.com> || @piniphone
+###
+
+
+Lungo.RouterTablet = do (lng = Lungo) ->
+
+  C                   = lng.Constants
+  HASHTAG             = "#"
+  _history            = []
+  _animating          = false
+
+  ###
+  Navigate to a <section>.
+  @method   section
+  @param    {string} Id of the <section>
+  ###
+  section = (section_id) ->
+    return false if _animating
+    current = lng.Element.Cache.section
+    if _notCurrentTarget current, section_id
+      query = C.ELEMENT.SECTION + HASHTAG + section_id
+      future = if current then current.siblings(query) else lng.dom(query)
+      if future.length
+        _show future, current
+        step section_id
+        do _url unless Lungo.Config.history is false
+        do _updateNavigationElements
+    # else do lng.Aside.hide
+
+  ###
+  Return to previous section.
+  @method   back
+  ###
+  back = (animating = true) ->
+    return false if _animating
+    do _removeLast
+    current = lng.Element.Cache.section
+    query = C.ELEMENT.SECTION + HASHTAG + history()
+    future = current.siblings(query)
+    if future.length
+      _show future, current, true, animating
+      do _url unless Lungo.Config.history is false
+      do _updateNavigationElements
+
+  ###
+  Displays the <article> in a particular <section>.
+  @method   article
+  @param    {string} <section> Id
+  @param    {string} <article> Id
+  ###
+  article = (section_id, article_id, element) ->
+    if not _sameSection() then back false
+    target = lng.dom "article##{article_id}"
+    if target.length > 0
+      section = target.closest C.ELEMENT.SECTION
+      lng.Router.section(section.attr("id"))
+      section.children("#{C.ELEMENT.ARTICLE}.#{C.CLASS.ACTIVE}").removeClass(C.CLASS.ACTIVE).trigger C.TRIGGER.UNLOAD
+      target.addClass(C.CLASS.ACTIVE).trigger(C.TRIGGER.LOAD)
+      # lng.Element.Cache.article.removeClass(C.CLASS.ACTIVE).trigger C.TRIGGER.UNLOAD
+      # lng.Element.Cache.article = target.addClass(C.CLASS.ACTIVE).trigger(C.TRIGGER.LOAD)
+
+      if element?.data(C.ATTRIBUTE.TITLE)?
+        # lng.Element.Cache.section.find(C.QUERY.TITLE).text element.data(C.ATTRIBUTE.TITLE)
+        section.find(C.QUERY.TITLE).text element.data(C.ATTRIBUTE.TITLE)
+      do _url unless Lungo.Config.history is false
+      _updateNavigationElements article_id
+
+  ###
+  Triggered when <section> animation ends. Reset animation classes of section and aside
+  @method   animationEnd
+  @param    {eventObject}
+  ###
+  animationEnd = (event) ->
+    section = lng.dom(event.target)
+    direction = section.data(C.ATTRIBUTE.DIRECTION)
+    if direction
+      section.removeClass C.CLASS.SHOW if direction is "out" or direction is "back-out"
+      section.removeAttr "data-#{C.ATTRIBUTE.DIRECTION}"
+    if section.hasClass("asideHidding")
+      section.removeClass("asideHidding").removeClass("aside")
+    if section.hasClass("asideShowing")
+      section.removeClass("asideShowing").addClass("aside")
+    if section.hasClass("shadowing")
+      section.removeClass("shadowing").addClass("shadow")
+    if section.hasClass("unshadowing")
+      section.removeClass("unshadowing").removeClass("shadow")
+
+    _animating = false
+
+  ###
+  Create a new element to the browsing history based on the current section id.
+  @method step
+  @param  {string} Id of the section
+  ###
+  step = (section_id) -> _history.push section_id if section_id isnt history()
+
+  ###
+  Returns the current browsing history section id.
+  @method history
+  @return {string} Current section id
+  ###
+  history = -> _history[_history.length - 1]
+
+  ###
+  Private methods
+  ###
+  _show = (future, current, backward, animating = true) ->
+    if not backward and not _sameSection() then back false
+    if current?
+      if backward
+        if animating then current.data(C.ATTRIBUTE.DIRECTION, "back-out")
+        else current.removeClass("show")
+      else
+        future.addClass(C.CLASS.SHOW)
+        future.data(C.ATTRIBUTE.DIRECTION, "in") if future.data(C.TRANSITION.ATTR)
+
+    lng.Section.show current, future
+    do _checkSectionAside if animating
+
+
+  _checkSectionAside = (section) ->
+    aside_id = lng.Element.Cache.section?.data("aside")
+    is_other_aside = aside_id isnt lng.Element.Cache.aside?.attr("id")
+    lng.Aside.hide (-> lng.Aside.show aside_id)
+
+
+  _sameSection = ->
+    if not event or not lng.Element.Cache.section then return true
+    dispacher_section = lng.dom(event.target).closest("section,aside")
+    same = dispacher_section.attr("id") is lng.Element.Cache.section.attr("id")
+    return same
+
+  _notCurrentTarget = (current, id) -> current?.attr(C.ATTRIBUTE.ID) isnt id
+
+  _url = ->
+    _hashed_url = ""
+    _hashed_url += "#{section}/" for section in _history
+    _hashed_url += lng.Element.Cache.article.attr "id"
+    setTimeout (-> window.location.hash = _hashed_url), 0
+
+  _updateNavigationElements = (article_id) ->
+    article_id = lng.Element.Cache.article.attr(C.ATTRIBUTE.ID) unless article_id
+    # Active visual signal for elements
+    links = lng.dom(C.QUERY.ARTICLE_ROUTER).removeClass(C.CLASS.ACTIVE)
+    links.filter("[data-view-article=#{article_id}]").addClass(C.CLASS.ACTIVE)
+    # Hide/Show elements in current article
+    nav = lng.Element.Cache.section.find(C.QUERY.ARTICLE_REFERENCE).addClass C.CLASS.HIDE
+    nav.filter("[data-article~='#{article_id}']").removeClass C.CLASS.HIDE
+
+  _removeLast = ->
+    if _history.length > 1
+      _history.length -= 1
+
+
+  section : section
+  back    : back
+  article : article
+  history : history
+  step    : step
+  animationEnd : animationEnd
+
+

+ 11 - 31
src/modules/Lungo.Section.coffee

@@ -7,12 +7,12 @@ Initialize the <articles> layout of a certain <section>
 @author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
 ###
 
-Lungo.Section = do(lng = Lungo) ->
-  C = lng.Constants
+Lungo.Section = do (lng = Lungo) ->
 
-  show = (current, target) ->
-    if lng.DEVICE is C.DEVICE.PHONE then _phone target else _tablet current, target
+  C = lng.Constants
 
+  show = (current, target, backward=false) ->
+    if lng.DEVICE is C.DEVICE.PHONE then _phone target else _tablet current, target, backward
     lng.Element.Cache.section = target
 
     active_article = target.find "#{C.ELEMENT.ARTICLE}.#{C.CLASS.ACTIVE}"
@@ -20,41 +20,21 @@ Lungo.Section = do(lng = Lungo) ->
       active_article = target.find(C.ELEMENT.ARTICLE).first().addClass(C.CLASS.ACTIVE)
 
     lng.Element.Cache.article = active_article
-    lng.Element.Cache.aside = lng.Aside.active target
-    if target.hasClass "aside" then lng.Aside.show()
-
     current.trigger C.TRIGGER.UNLOAD if current
     target.trigger C.TRIGGER.LOAD
 
-
-  defineTransition = (target, current) ->
-    target_transition = target.data C.ATTRIBUTE.TRANSITION
-    if target_transition
-      _assignTransitionOrigin current
-      assignTransition current, target_transition
-
-
-  assignTransition = (section, transitionName) ->
-    section.data C.ATTRIBUTE.TRANSITION, transitionName
-
-
   ###
   Private methods
   ###
   _phone = (target) ->
-    target.removeClass(C.CLASS.HIDE).addClass(C.CLASS.SHOW)
-
-  _tablet = (current, target) ->
-    children = current.data C.ATTRIBUTE.CHILDREN if current
-    if current and (not children or children.indexOf(target.attr(C.ATTRIBUTE.ID)) is -1)
-      current.addClass C.CLASS.HIDE
-      setTimeout (->current.removeClass(C.CLASS.SHOW).removeClass(C.CLASS.HIDE)), C.TRANSITION.DURATION
+    target.addClass(C.CLASS.SHOW)
 
-    setTimeout (-> target.addClass(C.CLASS.SHOW)), C.TRANSITION.DURATION
+  _tablet = (current, target, backward) ->
+    target.addClass(C.CLASS.SHOW)
+    # if current and (not children or children.indexOf(target.attr(C.ATTRIBUTE.ID)) is -1)
+    #   current.addClass C.CLASS.HIDE
+    #   setTimeout (->current.removeClass(C.CLASS.SHOW).removeClass(C.CLASS.HIDE)), C.TRANSITION.DURATION
+    # setTimeout (-> target.addClass(C.CLASS.SHOW)), C.TRANSITION.DURATION
 
-  _assignTransitionOrigin = (section) ->
-    section.data C.TRANSITION.ORIGIN, section.data(C.TRANSITION.ATTR)
 
   show: show
-  defineTransition: defineTransition
-  assignTransition: assignTransition

+ 49 - 0
src/stylesheets/lungo.animation.aside.styl

@@ -0,0 +1,49 @@
+@import "__init.styl"
+
+BOUNCE_DIST = 8
+
+section
+  &[data-aside-left="show"]
+    vendor(animation-name, sectionAsideLeftShow)
+  &[data-aside-left="hide"]
+    vendor(animation-name, sectionAsideLeftHide)
+  &[data-aside-right="show"]
+    vendor(animation-name, sectionAsideRightShow)
+  &[data-aside-right="hide"]
+    vendor(animation-name, sectionAsideRightHide)
+
+aside
+  &[data-transition=right]
+    right: 0px
+
+  &[data-aside-left="hide"]
+    vendor(animation-name, asideLeftHide)
+  &[data-aside-left="show"]
+    vendor(animation-name, asideLeftHide)
+
+
+@keyframes sectionAsideLeftShow
+  from { transform translateX(0) }
+  60%  { transform translateX(ASIDE_WIDTH + BOUNCE_DIST) }
+  to   { transform translateX(ASIDE_WIDTH) }
+
+@keyframes sectionAsideLeftHide
+  from { transform translateX(ASIDE_WIDTH) }
+  25%  { transform translateX(ASIDE_WIDTH + BOUNCE_DIST) }
+  to   { transform translateX(0) }
+
+@keyframes sectionAsideRightShow
+  from { transform translateX(0) }
+  60%  { transform translateX(-(ASIDE_WIDTH) - BOUNCE_DIST) }
+  to   { transform translateX(-(ASIDE_WIDTH)) }
+
+@keyframes sectionAsideRightHide
+  from { transform translateX(-(ASIDE_WIDTH)) }
+  25%  { transform translateX(-(ASIDE_WIDTH) - BOUNCE_DIST) }
+  to   { transform translateX(0) }
+
+// =============================================
+
+@keyframes asideLeftHide
+  from { transform translateX(0) }
+  to   { transform translateX(-(ASIDE_WIDTH)) }

+ 29 - 0
src/stylesheets/lungo.animation.cover.styl

@@ -0,0 +1,29 @@
+@import "__init.styl"
+
+TRANSLATE_Y = -18%
+TRANSLATE_Z = -150px
+ROTATE_X    = 20deg
+
+[data-transition="cover"]
+  &[data-direction="in"]
+    vendor(animation-name, coverIn)
+  &[data-direction="out"]
+    vendor(animation-name, coverOut)
+  &[data-direction="back-in"]
+    vendor(animation-name, coverInBack)
+  &[data-direction="back-out"]
+    vendor(animation-name, coverOutBack)
+
+
+@keyframes coverIn
+  from { transform: translateY(110%) }
+
+@keyframes coverOut
+  to { transform: rotateX(ROTATE_X) translateZ(TRANSLATE_Z) translateY(TRANSLATE_Y) }
+
+@keyframes coverInBack
+  from { transform: rotateX(ROTATE_X) translateZ(TRANSLATE_Z) translateY(TRANSLATE_Y) }
+
+@keyframes coverOutBack
+  to { transform: translateY(110%) }
+

+ 30 - 0
src/stylesheets/lungo.animation.fade.styl

@@ -0,0 +1,30 @@
+@import "__init.styl"
+
+.fadeIn
+  vendor(animation-name, fadeIn)
+  vendor(animation-duration, TRANSITION_TIME)
+  vendor(animation-timing-function, DEFAULT_TRANSITION)
+.fadeOut
+  vendor(animation-name, fadeOut)
+  vendor(animation-duration, TRANSITION_TIME)
+  vendor(animation-timing-function, DEFAULT_TRANSITION)
+.fadeInBack
+  vendor(animation-name, fadeInBack)
+  vendor(animation-duration, TRANSITION_TIME)
+  vendor(animation-timing-function, DEFAULT_TRANSITION)
+.fadeOutBack
+  vendor(animation-name, fadeOutBack)
+  vendor(animation-duration, TRANSITION_TIME)
+  vendor(animation-timing-function, DEFAULT_TRANSITION)
+
+@keyframes fadeIn
+  from { opacity: 0 }
+
+@keyframes fadeOut
+  to { opacity: 1 }
+
+@keyframes fadeInBack
+  from { opacity: 0 }
+
+@keyframes fadeOutBack
+  to { opacity: 0 }

+ 33 - 0
src/stylesheets/lungo.animation.slide.styl

@@ -0,0 +1,33 @@
+@import "__init.styl"
+
+SCALE = .8
+
+[data-transition="slide"]
+  &[data-direction="in"]
+    z-index: 2
+    vendor(animation-name, slideIn)
+  &[data-direction="out"]
+    z-index: 1
+    vendor(animation-name, slideOut)
+  &[data-direction="back-in"]
+    z-index: 1
+    vendor(animation-name, slideBackIn)
+  &[data-direction="back-out"]
+    z-index: 2
+    vendor(animation-name, slideBackOut)
+
+@keyframes slideIn
+  from { transform: translateX(100%); opacity: 0 }
+  to   { transform: translateX(0); opacity: 1 }
+
+@keyframes slideOut
+  from { transform: scale(1); opacity: 1 }
+  to   { transform: scale(SCALE); opacity: 0 }
+
+@keyframes slideBackOut
+  from { transform: translateX(0); opacity: 1 }
+  to   { transform: translateX(100%); opacity: 0 }
+
+@keyframes slideBackIn
+  from { transform: scale(SCALE); opacity: 0 }
+  to   { transform: scale(1); opacity: 1 }

+ 20 - 64
src/stylesheets/lungo.media.phone.styl

@@ -1,9 +1,13 @@
+@import "__init.styl"
 
 /* ==== Any phone ==== */
 
 
 @media only screen and (max-width: 767px)
   body
+    vendor(perspective, 800px)
+    vendor(transform-style, preserve-3d)
+
     &[data-position="absolute"] > section
       position: absolute
     &[data-position="fixed"] > section
@@ -17,68 +21,20 @@
       &:not([data-transition]).show
         display: block
 
-      &.show.aside
-        &:not(.right)
-          transform translateX(ASIDE_WIDTH)
-        &.right
-          transform translateX(-(ASIDE_WIDTH))
-      &.show.hide
-        z-index: -1
-
-      &[data-transition]
-        display-box()
-        transition-property opacity, z-index, transform,        scale, opacity
-        transition-duration TRANSITION_TIME
-        transition-timing-function DEFAULT_TRANSITION
-        backface-visibility hidden
-
-      /* Transition: SLIDE */
-      &[data-transition="slide"]
+      // &.show.aside
+      //   &:not(.right)
+      //     transform translateX(ASIDE_WIDTH)
+      //   &.right
+      //     transform translateX(-(ASIDE_WIDTH))
+      // &.show.hide
+      //   z-index: -1
+
+    & [data-transition], & [data-aside-transition]
+      display-box()
+      backface-visibility hidden
+      vendor(animation-duration, TRANSITION_TIME)
+      vendor(animation-timing-function, DEFAULT_TRANSITION)
+      vendor(animation-fill-mode, forwards)
+      visibility: hidden
+      &.show
         visibility: visible
-        z-index: 2
-        &.show, &:first-child
-          transform translateX(0%)
-          z-index: 1
-        &:not(first-child)
-          transform translateX(100%)
-        &.hide
-          transform scale(0.9)
-          z-index: -1
-          &:not(.last)
-            opacity: 0
-            transition none !important
-          &.last
-            opacity: 0.5 !important
-
-      /* Transition: COVER */
-      &[data-transition="cover"]
-        transform translateY(100%)
-        &.show, &.hide
-          transform translateY(0%)
-        &.hide
-          transform scale(0.9)
-          z-index: -1
-          &:not(.last)
-            opacity: 0
-            visibility: hidden
-          &.last
-            opacity: 0.2
-
-      /* Transition: POP */
-      &[data-transition="pop"]
-        opacity: 0
-        transform scale(1.15)
-        &.show
-          transform scale(1)
-          opacity: 1
-        &.hide
-          transform scale(0.9)
-          opacity: 0
-
-      /* Transition: FADE */
-      &[data-transition="fade"]
-        opacity: 0
-        &:first-child, &.show
-          opacity: 1
-        &:hide
-          opacity: 0

+ 57 - 34
src/stylesheets/lungo.media.tablet.styl

@@ -1,55 +1,78 @@
+@import "__init.styl"
+
+
 /* ==== Tablet ==== */
 @media only screen and (min-width: 768px)
   body
     display-box()
     box-orient(horizontal)
     overflow: hidden
+    vendor(perspective, 800px)
+    vendor(transform-style, preserve-3d)
+
+    & > section, & > aside
+      backface-visibility hidden
+      vendor(animation-timing-function, DEFAULT_TRANSITION)
+      vendor(animation-duration, TRANSITION_TIME)
+      vendor(animation-fill-mode, forwards)
 
     & > aside
-      transform translateX(-100%)
-      transition-property transform
-      transition-duration TRANSITION_TIME
-      margin-right: -(ASIDE_WIDTH)
+      position: absolute
+      z-index: 0
+      left: 0
+      top: 0
+      visibility: hidden
       &.show
-        transform translateX(0px)
-        margin-right:0
-      &.hide
-        transform translateX(-100%)
-        margin-right: -(ASIDE_WIDTH) !important
+        visibility: visible
 
     & > section
+      z-index: 1
       display: none
-      opacity: 0
-      ordinal-group(2)
-      transform translateX(100%)
       &.show
-        animation showing TRANSITION_TIME
-        animation-fill-mode forwards
         display-box()
-      &.hide
-        animation hiding TRANSITION_TIME
+
+      &.asideShowing
+        z-index: 2
+        vendor(animation-name, withAside)
+      &.asideHidding
+        vendor(animation-name, withoutAside)
+      &.aside
+        z-index: 2
+        transform translateX(ASIDE_WIDTH)
+
+      &.shadowing
+        vendor(animation-name, withAsideOpacity)
+      &.unshadowing
+        vendor(animation-name, withoutAsideOpacity)
+      &.shadow
+        transform translateX(ASIDE_WIDTH)
+        opacity: .6
+
 
       &:not([data-children])
         box-flex(1)
+        &[data-aside]
+          width: 500px !important
+          color: red !important
 
       &[data-children]
         width: 320px
 
-      & [data-view-aside]
-        display: none !important
-
-@-webkit-keyframes showing
-  0%
-    opacity: 0
-    transform translateX(100%)
-  100%
-    opacity: 1
-    transform translateX(0%)
-
-@-webkit-keyframes hiding
-  0%
-    opacity: 1
-    transform translateX(0%)
-  100%
-    opacity: 0
-    transform translateX(100%)
+
+
+@keyframes withAside
+  0%   {transform translateX(0)}
+  100% {transform translateX(ASIDE_WIDTH)}
+
+@keyframes withoutAside
+  0%   {transform translateX(ASIDE_WIDTH)}
+  100% {transform translateX(0)}
+
+@keyframes withAsideOpacity
+  0%   {transform translateX(0)}
+  100% {transform translateX(ASIDE_WIDTH); opacity: .6;}
+
+@keyframes withoutAsideOpacity
+  0%   {transform translateX(ASIDE_WIDTH); opacity: .6;}
+  100% {transform translateX(0)}
+