From b98f329fdd625d9a46d913fa52bb40f80e281bac Mon Sep 17 00:00:00 2001
From: "michael.danielczok" <michael@pcsg.de>
Date: Mon, 23 May 2022 15:23:22 +0200
Subject: [PATCH] feat: Show animation added [FloatedNav]

---
 bin/Controls/FloatedNav.js            | 169 ++++++++++++++++++++++++++
 src/QUI/Menu/Controls/FloatedNav.css  |  26 ++--
 src/QUI/Menu/Controls/FloatedNav.html |  51 ++++----
 src/QUI/Menu/Controls/FloatedNav.php  | 107 ++++++++++++++--
 4 files changed, 308 insertions(+), 45 deletions(-)
 create mode 100644 bin/Controls/FloatedNav.js

diff --git a/bin/Controls/FloatedNav.js b/bin/Controls/FloatedNav.js
new file mode 100644
index 0000000..f3dcfcf
--- /dev/null
+++ b/bin/Controls/FloatedNav.js
@@ -0,0 +1,169 @@
+/**
+ * @module package/quiqqer/menu/bin/Controls/FloatedNav
+ * @author www.pcsg.de (Michael Danielczok)
+ *
+ * @require qui/QUI
+ * @require qui/controls/Control
+ */
+define('package/quiqqer/menu/bin/Controls/FloatedNav', [
+
+    'qui/QUI',
+    'qui/controls/Control',
+    URL_OPT_DIR + 'bin/quiqqer-asset/animejs/animejs/lib/anime.min.js',
+
+], function (QUI, QUIControl, anime) {
+    'use strict';
+
+    return new Class({
+
+        Extends: QUIControl,
+        Type   : 'package/quiqqer/menu/bin/Controls/FloatedNav',
+
+        Binds: [
+            '$onImport'
+        ],
+
+        options: {
+            pos              : 'right', // right, left
+            animationtype    : 'showAll', // showAll (show entire control), showOneByOne (show each entry one by one)
+            animationeasing  : 'easeOutExpo', // see easing names on https://easings.net/
+            animationduration: 500, // number
+        },
+
+        initialize: function (options) {
+            this.parent(options);
+
+            this.addEvents({
+                onImport: this.$onImport
+            });
+
+            this.$Nav             = null;
+            this.$entries         = null;
+            this.$pos             = 'right';
+            this.$animationType   = 'showAll';
+            this.$animationEasing = 'easeOutExpo';
+        },
+
+        /**
+         * event: on import
+         */
+        $onImport: function () {
+            this.$Nav = this.getElm();
+
+            if (this.$Nav.get('data-qui-options-animationtype')) {
+                this.$animationType = this.$Nav.get('data-qui-options-animationtype');
+            }
+
+            if (this.$Nav.get('data-qui-options-animationeasing')) {
+                this.$animationEasing = this.$getAnimationName(this.$Nav.get('data-qui-options-animationeasing'));
+            }
+
+            // animation type
+            switch (this.$animationType) {
+                case 'showAll':
+                    this.$Nav.setStyles({
+                        visibility: 'visible',
+                        right     : -this.$Nav.getSize().x - 50
+                    })
+
+                    this.$show(this.$Nav);
+                    break;
+
+                case 'showOneByOne':
+                    this.$entries = this.$Nav.querySelectorAll('.quiqqer-floatedNav-entry');
+
+                    this.$entries.forEach(($Entry) => {
+                        $Entry.setStyles({
+                            visibility: 'visible',
+                            transform : 'translateX(100px)'
+                        });
+                    })
+
+                    this.$showOneByOne(this.$entries);
+                    break;
+            }
+        },
+
+        /**
+         * Show nav entries one by one
+         *
+         * @param entries {HTMLCollection}
+         */
+        $showOneByOne: function (entries) {
+            anime({
+                targets   : entries,
+                translateX: 0,
+                duration  : 500,
+                easing    : this.$animationEasing,
+                delay     : anime.stagger(100, {start: 750})
+            });
+        },
+
+        /**
+         * Show nav
+         *
+         * @param Elm {HTMLElement}
+         */
+        $show: function (Elm) {
+            anime({
+                targets : Elm,
+                right   : 0,
+                delay   : 750,
+                duration: 500,
+                easing  : this.$animationEasing
+            });
+        },
+
+        /**
+         * Get correct easing name for animation
+         * https://easings.net/
+         *
+         * @param easingName {string}
+         * @return {string}
+         */
+        $getAnimationName: function (easingName) {
+            switch (easingName) {
+                case 'easeInQuad':
+                case 'easeInCubic':
+                case 'easeInQuart':
+                case 'easeInQuint':
+                case 'easeInSine':
+                case 'easeInExpo':
+                case 'easeInCirc':
+                case 'easeInBack':
+                case 'easeOutQuad':
+                case 'easeOutCubic':
+                case 'easeOutQuart':
+                case 'easeOutQuint':
+                case 'easeOutSine':
+                case 'easeOutExpo':
+                case 'easeOutCirc':
+                case 'easeOutBack':
+                case 'easeInBounce':
+                case 'easeInOutQuad':
+                case 'easeInOutCubic':
+                case 'easeInOutQuart':
+                case 'easeInOutQuint':
+                case 'easeInOutSine':
+                case 'easeInOutExpo':
+                case 'easeInOutCirc':
+                case 'easeInOutBack':
+                case 'easeInOutBounce':
+                case 'easeOutBounce':
+                case 'easeOutInQuad':
+                case 'easeOutInCubic':
+                case 'easeOutInQuart':
+                case 'easeOutInQuint':
+                case 'easeOutInSine':
+                case 'easeOutInExpo':
+                case 'easeOutInCirc':
+                case 'easeOutInBack':
+                case 'easeOutInBounce':
+                    return easingName;
+
+                default:
+                    return 'easeOutExpo';
+            }
+        }
+    });
+});
\ No newline at end of file
diff --git a/src/QUI/Menu/Controls/FloatedNav.css b/src/QUI/Menu/Controls/FloatedNav.css
index 40b20b6..a414672 100644
--- a/src/QUI/Menu/Controls/FloatedNav.css
+++ b/src/QUI/Menu/Controls/FloatedNav.css
@@ -23,7 +23,6 @@
 /* control */
 /***********/
 .quiqqer-floatedNav {
-    background: #fff;
     position: fixed;
     top: 50%;
     transform: translateY(-50%);
@@ -39,7 +38,7 @@
 }
 
 .quiqqer-floatedNav-entry {
-    transition: 0.2s all ease;
+    /*transition: 0.2s all ease;*/
 }
 
 .quiqqer-floatedNav-entry-inner {
@@ -94,28 +93,41 @@
     filter: brightness(90%);
 }
 
+
 /***********/
 /* Designs */
 /***********/
 
 /* Design: Bar with icons */
-.quiqqer-floatedNav__iconsBar {
+.quiqqer-floatedNav__design-iconsBar {
+    background: #fff;
     border-bottom-left-radius: 0.75rem;
     border-top-left-radius: 0.75rem;
     box-shadow: -3px 3px 8px rgb(0 0 0 / 30%);
     padding: var(--quiqqer-floatedNav-spacing);
 }
 
-.quiqqer-floatedNav__iconsBar .quiqqer-floatedNav-entry-inner,
-.quiqqer-floatedNav__iconsBar .quiqqer-bricks-languageswitch-flag {
+.quiqqer-floatedNav__design-iconsBar .quiqqer-floatedNav-entry-inner,
+.quiqqer-floatedNav__design-iconsBar .quiqqer-bricks-languageswitch-flag {
     border-radius: var(--qui-btn-border-radius, 5px);
 }
 
-.quiqqer-floatedNav__iconsBar .quiqqer-floatedNav-entry:not(:last-child) .quiqqer-floatedNav-entry-inner {
+.quiqqer-floatedNav__design-iconsBar .quiqqer-floatedNav-entry:not(:last-child) .quiqqer-floatedNav-entry-inner {
     margin-bottom: var(--quiqqer-floatedNav-spacing);
 }
 
 /* Design: flat */
-.quiqqer-floatedNav__flat .quiqqer-floatedNav-entry:not(:last-child) {
+.quiqqer-floatedNav__design-flat .quiqqer-floatedNav-entry:not(:last-child) {
     margin-bottom: 2px;
 }
+
+/*************/
+/* Animation */
+/*************/
+.quiqqer-floatedNav__animation-showAll {
+    visibility: hidden;
+}
+
+.quiqqer-floatedNav__animation-showOneByOne .quiqqer-floatedNav-entry {
+    visibility: hidden;
+}
\ No newline at end of file
diff --git a/src/QUI/Menu/Controls/FloatedNav.html b/src/QUI/Menu/Controls/FloatedNav.html
index aea686f..1bd3c3d 100644
--- a/src/QUI/Menu/Controls/FloatedNav.html
+++ b/src/QUI/Menu/Controls/FloatedNav.html
@@ -1,28 +1,27 @@
-<nav class="quiqqer-floatedNav {$design} {$size} {$posX}">
-    {foreach $children as $Child}
-        {assign var=hasUrl value=1}
-        {if !$Child->getUrl()}
-            {assign var=hasUrl value=0}
-        {/if}
-        {if $Child->getIcon() && $Child->getIcon()|strpos:'image.php' !== 0}
-            <div class="quiqqer-floatedNav-entry quiqqer-floatedNav-entry__id-{$Child->getIdentifier()} {if !$hasUrl}quiqqer-floatedNav-entry__noUrl{/if}">
-                {if $Child->getUrl()}
-                    <a href="{$Child->getUrl()}"
-                       class="quiqqer-floatedNav-entry-inner"
-                       title="{$Child->getTitleAttribute()|escape:'html'}"
-                       {if $Child->getTarget()}target="{$Child->getTarget()}"{/if}
-                    >
-                        {image src=$Child->getIcon() onlyicon=1}
-                    </a>
-                {else}
-                    <span class="quiqqer-floatedNav-entry-inner" title="{$Child->getTitleAttribute()|escape:'html'}">
+{foreach $children as $Child}
+    {assign var=hasUrl value=1}
+    {if !$Child->getUrl()}
+        {assign var=hasUrl value=0}
+    {/if}
+    {if $Child->getIcon() && $Child->getIcon()|strpos:'image.php' !== 0}
+        <div class="quiqqer-floatedNav-entry quiqqer-floatedNav-entry__id-{$Child->getIdentifier()} {if !$hasUrl}quiqqer-floatedNav-entry__noUrl{/if}">
+            {if $Child->getUrl()}
+                <a href="{$Child->getUrl()}"
+                   class="quiqqer-floatedNav-entry-inner"
+                   title="{$Child->getTitleAttribute()|escape:'html'}"
+                   {if $Child->getTarget()}target="{$Child->getTarget()}"{/if}
+                >
                     {image src=$Child->getIcon() onlyicon=1}
-                </span>
-                {/if}
-            </div>
-        {/if}
-    {/foreach}
-    {if $LangSwitch}
-        {$LangSwitch->create()}
+                </a>
+            {else}
+                <span class="quiqqer-floatedNav-entry-inner" title="{$Child->getTitleAttribute()|escape:'html'}">
+                {image src=$Child->getIcon() onlyicon=1}
+            </span>
+            {/if}
+        </div>
     {/if}
-</nav>
\ No newline at end of file
+{/foreach}
+
+{if $LangSwitch}
+    {$LangSwitch->create()}
+{/if}
\ No newline at end of file
diff --git a/src/QUI/Menu/Controls/FloatedNav.php b/src/QUI/Menu/Controls/FloatedNav.php
index 72fec77..517383a 100644
--- a/src/QUI/Menu/Controls/FloatedNav.php
+++ b/src/QUI/Menu/Controls/FloatedNav.php
@@ -25,11 +25,15 @@ public function __construct($attributes = [])
     {
         // default options
         $this->setAttributes([
-            'menuId'         => false,
-            'posX'           => 'right', // right, left
-            'size'           => 'medium', // small, medium, large
-            'design'         => 'iconBar', // iconBar, flat
-            'showLangSwitch' => false
+            'class'           => 'quiqqer-floatedNav',
+            'nodeName'        => 'nav',
+            'menuId'          => false,
+            'posX'            => 'right', // right, left
+            'size'            => 'medium', // small, medium, large
+            'design'          => 'iconBar', // iconBar, flat
+            'animationType'   => false, // false, showOneByOne (show entire control), showSingle (show each entry one by one)
+            'animationEasing' => 'easeOutExpo', // see easing names on https://easings.net/
+            'showLangSwitch'  => false
         ]);
 
         parent::__construct($attributes);
@@ -46,9 +50,16 @@ public function __construct($attributes = [])
      */
     public function getBody()
     {
-        $Engine          = QUI::getTemplateManager()->getEngine();
-        $IndependentMenu = Independent\Handler::getMenu($this->getAttribute('menuId'));
-        $LangSwitch      = null;
+        $Engine     = QUI::getTemplateManager()->getEngine();
+        $LangSwitch = null;
+
+        try {
+            $IndependentMenu = Independent\Handler::getMenu($this->getAttribute('menuId'));
+        } catch (QUI\Exception $Exception) {
+            QUI\System\Log::writeException($Exception);
+
+            return '';
+        }
 
         if (!$IndependentMenu) {
             return '';
@@ -66,13 +77,13 @@ public function getBody()
         }
 
         switch ($this->getAttribute('design')) {
-            case 'iconBar':
             case 'flat':
-                $design = 'quiqqer-floatedNav__'.$this->getAttribute('design');
+                $design = 'quiqqer-floatedNav__design-'.$this->getAttribute('design');
                 break;
 
+            case 'iconBar':
             default:
-                $design = 'quiqqer-floatedNav__iconsBar';
+                $design = 'quiqqer-floatedNav__design-iconsBar';
         }
 
         switch ($this->getAttribute('posX')) {
@@ -89,13 +100,33 @@ public function getBody()
         if ($this->getAttribute('showLangSwitch')) {
             try {
                 $LangSwitch = new QUI\Bricks\Controls\LanguageSwitches\Flags([
-                    'showFlags' => 0
+                    'showFlags' => 0,
+                    'class'     => 'quiqqer-floatedNav-entry'
                 ]);
             } catch (QUI\Exception $Exception) {
                 QUI\System\Log::writeException($Exception);
             }
         }
 
+        $animation = '';
+        if ($this->getAttribute('animationType')) {
+            switch ($this->getAttribute('animationType')) {
+                case 'showAll':
+                case 'showOneByOne':
+                    $this->setJavaScriptControlOption('position', 'right');
+                    $this->setJavaScriptControlOption('animationtype', $this->getAttribute('animationType'));
+                    $this->setJavaScriptControlOption('animationeasing', $this->getAnimationEasingName());
+                    $this->setJavaScriptControl('package/quiqqer/menu/bin/Controls/FloatedNav');
+                    $animation = 'quiqqer-floatedNav__animation-'.$this->getAttribute('animationType');
+                    break;
+            }
+        }
+
+        $this->addCSSClass($size);
+        $this->addCSSClass($design);
+        $this->addCSSClass($posX);
+        $this->addCSSClass($animation);
+
         $children = $IndependentMenu->getChildren();
 
         $Engine->assign([
@@ -109,4 +140,56 @@ public function getBody()
 
         return $Engine->fetch(dirname(__FILE__).'/FloatedNav.html');
     }
+
+    /**
+     * Get correct easing name for animation
+     * https://easings.net/
+     *
+     * @return false|mixed|string
+     */
+    public function getAnimationEasingName()
+    {
+        switch ($this->getAttribute('animationEasing')) {
+            case 'easeInQuad':
+            case 'easeInCubic':
+            case 'easeInQuart':
+            case 'easeInQuint':
+            case 'easeInSine':
+            case 'easeInExpo':
+            case 'easeInCirc':
+            case 'easeInBack':
+            case 'easeOutQuad':
+            case 'easeOutCubic':
+            case 'easeOutQuart':
+            case 'easeOutQuint':
+            case 'easeOutSine':
+            case 'easeOutExpo':
+            case 'easeOutCirc':
+            case 'easeOutBack':
+            case 'easeInBounce':
+            case 'easeInOutQuad':
+            case 'easeInOutCubic':
+            case 'easeInOutQuart':
+            case 'easeInOutQuint':
+            case 'easeInOutSine':
+            case 'easeInOutExpo':
+            case 'easeInOutCirc':
+            case 'easeInOutBack':
+            case 'easeInOutBounce':
+            case 'easeOutBounce':
+            case 'easeOutInQuad':
+            case 'easeOutInCubic':
+            case 'easeOutInQuart':
+            case 'easeOutInQuint':
+            case 'easeOutInSine':
+            case 'easeOutInExpo':
+            case 'easeOutInCirc':
+            case 'easeOutInBack':
+            case 'easeOutInBounce':
+                return $this->getAttribute('animationEasing');
+
+            default:
+                return 'easeOutExpo';
+        }
+    }
 }
-- 
GitLab