From 12784559316fc2c3860641bee9c6f8e2bc12c4ba Mon Sep 17 00:00:00 2001
From: Clement Ho <ClemMakesApps@gmail.com>
Date: Wed, 3 Aug 2016 22:20:08 -0500
Subject: [PATCH] Change logo animation to CSS

---
 CHANGELOG                                    |   1 +
 app/assets/javascripts/logo.js               |  42 +------
 app/assets/stylesheets/framework.scss        |   1 +
 app/assets/stylesheets/framework/header.scss |  32 +----
 app/assets/stylesheets/framework/logo.scss   | 118 +++++++++++++++++++
 app/assets/stylesheets/framework/mixins.scss |   5 +
 app/views/shared/_logo.svg                   |  16 +--
 7 files changed, 136 insertions(+), 79 deletions(-)
 create mode 100644 app/assets/stylesheets/framework/logo.scss

diff --git a/CHANGELOG b/CHANGELOG
index 3548115dff397..713e0e033d08e 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -3,6 +3,7 @@ Please view this file on the master branch, on stable branches it's out of date.
 v 8.12.0 (unreleased)
   - Add two-factor recovery endpoint to internal API !5510
   - Add font color contrast to external label in admin area (ClemMakesApps)
+  - Change logo animation to CSS (ClemMakesApps)
   - Change merge_error column from string to text type
   - Reduce contributions calendar data payload (ClemMakesApps)
   - Add `web_url` field to issue, merge request, and snippet API objects (Ben Boeckel)
diff --git a/app/assets/javascripts/logo.js b/app/assets/javascripts/logo.js
index 218f24fe908cd..e5d4fd44c96d5 100644
--- a/app/assets/javascripts/logo.js
+++ b/app/assets/javascripts/logo.js
@@ -1,50 +1,12 @@
 (function() {
-  var clearHighlights, currentTimer, defaultClass, delay, firstPiece, pieceIndex, pieces, start, stop, work;
-
   Turbolinks.enableProgressBar();
 
-  defaultClass = 'tanuki-shape';
-
-  pieces = ['path#tanuki-right-cheek', 'path#tanuki-right-eye, path#tanuki-right-ear', 'path#tanuki-nose', 'path#tanuki-left-eye, path#tanuki-left-ear', 'path#tanuki-left-cheek'];
-
-  pieceIndex = 0;
-
-  firstPiece = pieces[0];
-
-  currentTimer = null;
-
-  delay = 150;
-
-  clearHighlights = function() {
-    return $("." + defaultClass + ".highlight").attr('class', defaultClass);
-  };
-
   start = function() {
-    clearHighlights();
-    pieceIndex = 0;
-    if (pieces[0] !== firstPiece) {
-      pieces.reverse();
-    }
-    if (currentTimer) {
-      clearInterval(currentTimer);
-    }
-    return currentTimer = setInterval(work, delay);
+    $('.tanuki-logo').addClass('animate');
   };
 
   stop = function() {
-    clearInterval(currentTimer);
-    return clearHighlights();
-  };
-
-  work = function() {
-    clearHighlights();
-    $(pieces[pieceIndex]).attr('class', defaultClass + " highlight");
-    if (pieceIndex === pieces.length - 1) {
-      pieceIndex = 0;
-      return pieces.reverse();
-    } else {
-      return pieceIndex++;
-    }
+    $('.tanuki-logo').removeClass('animate');
   };
 
   $(document).on('page:fetch', start);
diff --git a/app/assets/stylesheets/framework.scss b/app/assets/stylesheets/framework.scss
index a306b8f3f2968..d5cca1b10fbf7 100644
--- a/app/assets/stylesheets/framework.scss
+++ b/app/assets/stylesheets/framework.scss
@@ -24,6 +24,7 @@
 @import "framework/issue_box.scss";
 @import "framework/jquery.scss";
 @import "framework/lists.scss";
+@import "framework/logo.scss";
 @import "framework/markdown_area.scss";
 @import "framework/mobile.scss";
 @import "framework/modal.scss";
diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss
index 0c607071840d2..afe4a276ae55e 100644
--- a/app/assets/stylesheets/framework/header.scss
+++ b/app/assets/stylesheets/framework/header.scss
@@ -2,16 +2,6 @@
  *  Application Header
  *
  */
-@mixin tanuki-logo-colors($path-color) {
-  fill: $path-color;
-  transition: all 0.8s;
-
-  &:hover,
-  &.highlight {
-    fill: lighten($path-color, 25%);
-    transition: all 0.1s;
-  }
-}
 
 header {
   transition: padding $sidebar-transition-duration;
@@ -25,7 +15,7 @@ header {
       margin: 8px 0;
       text-align: center;
 
-      #tanuki-logo, img {
+      .tanuki-logo, img {
         height: 36px;
       }
     }
@@ -205,26 +195,6 @@ header {
   }
 }
 
-#tanuki-logo {
-
-  #tanuki-left-ear,
-  #tanuki-right-ear,
-  #tanuki-nose {
-    @include tanuki-logo-colors($tanuki-red);
-  }
-
-  #tanuki-left-eye,
-  #tanuki-right-eye {
-    @include tanuki-logo-colors($tanuki-orange);
-  }
-
-  #tanuki-left-cheek,
-  #tanuki-right-cheek {
-    @include tanuki-logo-colors($tanuki-yellow);
-  }
-
-}
-
 @media (max-width: $screen-xs-max) {
   header .container-fluid {
     font-size: 18px;
diff --git a/app/assets/stylesheets/framework/logo.scss b/app/assets/stylesheets/framework/logo.scss
new file mode 100644
index 0000000000000..3ee3fb4cee5ad
--- /dev/null
+++ b/app/assets/stylesheets/framework/logo.scss
@@ -0,0 +1,118 @@
+@mixin unique-keyframes {
+  $animation-name: unique-id();
+  @include webkit-prefix(animation-name, $animation-name);
+
+  @-webkit-keyframes #{$animation-name} {
+    @content;
+  }
+  @keyframes #{$animation-name} {
+    @content;
+  }
+}
+
+@mixin tanuki-logo-colors($path-color) {
+  fill: $path-color;
+  transition: all 0.8s;
+
+  &:hover {
+    fill: lighten($path-color, 25%);
+    transition: all 0.1s;
+  }
+}
+
+@mixin tanuki-second-highlight-animations($tanuki-color) {
+  @include unique-keyframes {
+    10%, 80% {
+      fill: #{$tanuki-color}
+    }
+    20%, 90% {
+      fill: lighten($tanuki-color, 25%);
+    }
+  }
+}
+
+@mixin tanuki-forth-highlight-animations($tanuki-color) {
+  @include unique-keyframes {
+    30%, 60% {
+      fill: #{$tanuki-color};
+    }
+    40%, 70% {
+      fill: lighten($tanuki-color, 25%);
+    }
+  }
+}
+
+.tanuki-logo {
+
+  .tanuki-left-ear,
+  .tanuki-right-ear,
+  .tanuki-nose {
+    @include tanuki-logo-colors($tanuki-red);
+  }
+
+  .tanuki-left-eye,
+  .tanuki-right-eye {
+    @include tanuki-logo-colors($tanuki-orange);
+  }
+
+  .tanuki-left-cheek,
+  .tanuki-right-cheek {
+    @include tanuki-logo-colors($tanuki-yellow);
+  }
+
+  &.animate {
+    .tanuki-shape {
+      @include webkit-prefix(animation-duration, 1.5s);
+      @include webkit-prefix(animation-iteration-count, infinite);
+    }
+
+    .tanuki-left-cheek {
+      @include unique-keyframes {
+        0%, 10%, 100% {
+          fill: lighten($tanuki-yellow, 25%);
+        }
+        90% {
+          fill: $tanuki-yellow;
+        }
+      }
+    }
+
+    .tanuki-left-eye {
+      @include tanuki-second-highlight-animations($tanuki-orange);
+    }
+
+    .tanuki-left-ear {
+      @include tanuki-second-highlight-animations($tanuki-red);
+    }
+
+    .tanuki-nose {
+      @include unique-keyframes {
+        20%, 70% {
+          fill: $tanuki-red;
+        }
+        30%, 80% {
+          fill: lighten($tanuki-red, 25%);
+        }
+      }
+    }
+
+    .tanuki-right-eye {
+      @include tanuki-forth-highlight-animations($tanuki-orange);
+    }
+
+    .tanuki-right-ear {
+      @include tanuki-forth-highlight-animations($tanuki-red);
+    }
+
+    .tanuki-right-cheek {
+      @include unique-keyframes {
+        40% {
+          fill: $tanuki-yellow;
+        }
+        60% {
+          fill: lighten($tanuki-yellow, 25%);
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/framework/mixins.scss b/app/assets/stylesheets/framework/mixins.scss
index d2d60ed71967e..856642400a65f 100644
--- a/app/assets/stylesheets/framework/mixins.scss
+++ b/app/assets/stylesheets/framework/mixins.scss
@@ -129,3 +129,8 @@
   color: rgba(255, 255, 255, 0.3);
   background: rgba(255, 255, 255, 0.1);
 }
+
+@mixin webkit-prefix($property, $value) {
+  #{'-webkit-' + $property}: $value;
+  #{$property}: $value;
+}
diff --git a/app/views/shared/_logo.svg b/app/views/shared/_logo.svg
index b07f1c5603e6c..9b67422da2c25 100644
--- a/app/views/shared/_logo.svg
+++ b/app/views/shared/_logo.svg
@@ -1,9 +1,9 @@
-<svg width="36" height="36" id="tanuki-logo">
-  <path id="tanuki-right-ear" class="tanuki-shape" fill="#e24329" d="M2 14l9.38 9v-9l-4-12.28c-.205-.632-1.176-.632-1.38 0z"/>
-  <path id="tanuki-left-ear" class="tanuki-shape" fill="#e24329" d="M34 14l-9.38 9v-9l4-12.28c.205-.632 1.176-.632 1.38 0z"/>
-  <path id="tanuki-nose" class="tanuki-shape" fill="#e24329" d="M18,34.38 3,14 33,14 Z"/>
-  <path id="tanuki-right-eye" class="tanuki-shape" fill="#fc6d26" d="M18,34.38 11.38,14 2,14 6,25Z"/>
-  <path id="tanuki-left-eye" class="tanuki-shape" fill="#fc6d26" d="M18,34.38 24.62,14 34,14 30,25Z"/>
-  <path id="tanuki-right-cheek" class="tanuki-shape" fill="#fca326" d="M2 14L.1 20.16c-.18.565 0 1.2.5 1.56l17.42 12.66z"/>
-  <path id="tanuki-left-cheek" class="tanuki-shape" fill="#fca326" d="M34 14l1.9 6.16c.18.565 0 1.2-.5 1.56L18 34.38z"/>
+<svg width="36" height="36" class="tanuki-logo">
+  <path class="tanuki-shape tanuki-left-ear" fill="#e24329" d="M2 14l9.38 9v-9l-4-12.28c-.205-.632-1.176-.632-1.38 0z"/>
+  <path class="tanuki-shape tanuki-right-ear" fill="#e24329" d="M34 14l-9.38 9v-9l4-12.28c.205-.632 1.176-.632 1.38 0z"/>
+  <path class="tanuki-shape tanuki-nose" fill="#e24329" d="M18,34.38 3,14 33,14 Z"/>
+  <path class="tanuki-shape tanuki-left-eye" fill="#fc6d26" d="M18,34.38 11.38,14 2,14 6,25Z"/>
+  <path class="tanuki-shape tanuki-right-eye" fill="#fc6d26" d="M18,34.38 24.62,14 34,14 30,25Z"/>
+  <path class="tanuki-shape tanuki-left-cheek" fill="#fca326" d="M2 14L.1 20.16c-.18.565 0 1.2.5 1.56l17.42 12.66z"/>
+  <path class="tanuki-shape tanuki-right-cheek" fill="#fca326" d="M34 14l1.9 6.16c.18.565 0 1.2-.5 1.56L18 34.38z"/>
 </svg>
-- 
GitLab