changeset 487:1ec071454790

web: UX improvements for the sidebar menu. - Open/close the menu on click instead of mouse hover, so it's more friendly to mobile/touch devices. - Rework how the menu lock works.
author Ludovic Chabant <ludovic@chabant.com>
date Thu, 01 Nov 2018 21:25:23 -0700
parents bba13de7a7d1
children 40c778469672
files wikked/assets/css/wikked/nav.less wikked/assets/js/wikked/app.js wikked/templates/index.html wikked/templates/nav.html wikked/templates/special-nav.html wikked/views/__init__.py
diffstat 6 files changed, 89 insertions(+), 94 deletions(-) [+]
line wrap: on
line diff
--- a/wikked/assets/css/wikked/nav.less	Tue Oct 16 22:08:51 2018 -0700
+++ b/wikked/assets/css/wikked/nav.less	Thu Nov 01 21:25:23 2018 -0700
@@ -7,14 +7,9 @@
 
 .wrapper {
     transition: padding 200ms ease-in-out 0s;
+    padding-top: 3.6em;
     padding-left: 0;
 }
-.wrapper.wiki-menu-active {
-    padding-left: @wiki-menu-width !important;
-}
-.wrapper.wiki-menu-inactive {
-    padding-left: 0 !important;
-}
 
 .wiki-menu-a {
     color: @color-gray-light;
@@ -35,24 +30,21 @@
     }
 }
 
-#wiki-menu-pin {
+#wiki-menu-header {
     height: @wiki-shortcut-height;
     padding: 0 1.5em 0 @wiki-shortcut-width;
     text-align: right;
     color: @color-gray-medium;
     cursor: pointer;
 
-    &:hover {
+    i {
+        line-height: @wiki-shortcut-height;
+        display: none;
+    }
+    i:hover {
         color: @color-gray-light;
         text-shadow: #EEE 0 0 1em;
     }
-
-    span, i {
-        line-height: @wiki-shortcut-height;
-    }
-}
-#wiki-menu-pin.wiki-menu-pin-active {
-    color: @color-gray-light;
 }
 
 #wiki-menu {
@@ -90,17 +82,6 @@
     }
 }
 
-#wiki-menu.wiki-menu-active {
-    left: 0 !important;
-}
-#wiki-menu.wiki-menu-inactive {
-    left: -@wiki-menu-width !important;
-}
-#wiki-menu.wiki-menu-ext {
-    width: @wiki-menu-width-ext !important;
-    box-shadow: 4px 0px 10px rgba(0, 0, 0, 0.3);
-}
-
 #wiki-menu-shortcut {
     position: fixed !important;
     top: 0;
@@ -115,15 +96,42 @@
     cursor: pointer;
 }
 
-@media (min-width: 48em) {
-    // Hide the shortcut and move the horizontal menu down.
+#app.wiki-menu-active {
     #wiki-menu {
-        //left: 0;
+        left: 0 !important;
     }
-    .wrapper {
-        //padding-left: @wiki-menu-width;
+}
+#app.wiki-menu-inactive {
+    #wiki-menu {
+        left: -@wiki-menu-width !important;
     }
 }
+#app.wiki-menu-locked.wiki-menu-active .wrapper {
+    padding-left: @wiki-menu-width !important;
+}
+#app.wiki-menu-locked.wiki-menu-inactive .wrapper {
+    padding-left: 0 !important;
+}
+
+#wiki-menu.wiki-menu-ext {
+    width: @wiki-menu-width-ext !important;
+    box-shadow: 4px 0px 10px rgba(0, 0, 0, 0.3);
+}
+
+@media screen and (min-width: 48em) {
+    // Menu can be locked only on big enough screens.
+    #wiki-menu-header i {
+        display: block;
+    }
+}
+// If somehow we end up with a small screen where the lock icon is hidden,
+// but we still have the menu locked, then show the lock icon anyway.
+@media screen and (max-width: 48em) {
+    #app.wiki-menu-locked #wiki-menu-header i {
+        display: block;
+    }
+}
+
 
 // Search
 .search-result-hover {
--- a/wikked/assets/js/wikked/app.js	Tue Oct 16 22:08:51 2018 -0700
+++ b/wikked/assets/js/wikked/app.js	Thu Nov 01 21:25:23 2018 -0700
@@ -15,18 +15,19 @@
 
         // Cache some stuff for handling the menu.
         this.wikiBody = $('body');
+        this.wikiApp = $('#app');
         this.wikiMenu = $('#wiki-menu');
-        this.wikiMenuAndWrapper = $.merge(this.wikiMenu, $('#app .wrapper'));
+        this.wikiMenuLock = $('#wiki-menu-lock');
         this.isMenuActive = (this.wikiMenu.css('left') == '0px');
-        this.isMenuActiveLocked = false;
+        this.isMenuLocked = (this.wikiApp.hasClass('wiki-menu-locked'));
 
         // Hookup events.
         this.listen("#wiki-menu-shortcut", 'click', '_onMenuShortcutClick');
-        this.listen("#wiki-menu-pin", 'click', '_onMenuShortcutClick');
-        this.listen("#wiki-menu-shortcut", 'mouseenter', '_onMenuShortcutHover');
-        this.listen("#wiki-menu-shortcut", 'mouseleave', '_onMenuShortcutLeave');
-        this.listen("#wiki-menu", 'mouseenter', '_onMenuHover');
-        this.listen("#wiki-menu", 'mouseleave', '_onMenuLeave');
+        this.listen("#wiki-menu-lock", 'click', '_onMenuLockClick');
+        this.listen("#wiki-menu-lock", 'mouseenter', '_onMenuLockHoverLeave');
+        this.listen("#wiki-menu-lock", 'mouseleave', '_onMenuLockHoverLeave');
+        this.listen("#app .wrapper", 'click', '_onBackgroundClick');
+
         this.listen("#search-query", 'focus', '_searchQueryFocused');
         this.listen("#search-query", 'input', '_previewSearch');
         this.listen("#search-query", 'keyup', '_searchQueryChanged');
@@ -39,65 +40,50 @@
             _t[callback](e);
         });
     },
-    _setNavHiddenCookie: function(val) {
-        document.cookie = (
-                "wiki-hide-nav=" + val + "; " +
-                "path=/; expires=31 Dec 2100 UTC");
+
+    _toggleWikiMenu: function() {
+        this.isMenuActive = !this.isMenuActive;
+        if (this.isMenuActive) {
+            this.wikiApp.toggleClass('wiki-menu-inactive', false);
+            this.wikiApp.toggleClass('wiki-menu-active', true);
+        } else {
+            this.wikiApp.toggleClass('wiki-menu-active', false);
+            this.wikiApp.toggleClass('wiki-menu-inactive', true);
+        }
     },
     _onMenuShortcutClick: function(e) {
-        this.isMenuActive = !this.isMenuActive;
-        var val = this.isMenuActive ? "0" : "1";
-        this._setNavHiddenCookie(val);
-        this._toggleWikiMenuPin(this.isMenuActive);
-    },
-    _onMenuShortcutHover: function(e) {
-        if (!this.isMenuActive && !this.isMenuActiveLocked)
-            this._toggleWikiMenu(true);
+        this._toggleWikiMenu();
     },
-    _onMenuShortcutLeave: function(e) {
-        if (!this.isMenuActive && !this.isMenuActiveLocked)
-            this._toggleWikiMenu(false);
-    },
-    _onMenuHover: function(e) {
-        if (!this.isMenuActive && !this.isMenuActiveLocked)
-            this._toggleWikiMenu(true);
-    },
-    _onMenuLeave: function(e) {
-        if (!this.isMenuActive && !this.isMenuActiveLocked)
-            this._toggleWikiMenu(false);
+
+    _lockUnlockWikiMenu: function() {
+        var val = this.isMenuLocked ? "0" : "1";
+        document.cookie = (
+                "wiki-nav-locked=" + val + "; " +
+                "path=/; expires=31 Dec 2100 UTC");
+        this.wikiApp.toggleClass('wiki-menu-locked');
+        this.isMenuLocked = !this.isMenuLocked;
     },
-    _toggleWikiMenu: function(onOff) {
-        if (onOff) {
-            this.wikiMenuAndWrapper.toggleClass('wiki-menu-inactive', false);
-            this.wikiMenuAndWrapper.toggleClass('wiki-menu-active', true);
-        } else {
-            this.wikiMenuAndWrapper.toggleClass('wiki-menu-active', false);
-            this.wikiMenuAndWrapper.toggleClass('wiki-menu-inactive', true);
-        }
+    _onMenuLockClick: function(e) {
+        this._lockUnlockWikiMenu();
+    },
+
+    _onMenuLockHoverLeave: function(e) {
+        this.wikiMenuLock.toggleClass('fa-lock');
+        this.wikiMenuLock.toggleClass('fa-unlock');
     },
-    _toggleWikiMenuPin: function(onOff) {
-        $('#wiki-menu-pin').toggleClass('wiki-menu-pin-active', onOff);
-        var lockIcon = $('#wiki-menu-pin>i');
-        if (onOff)
-        {
-            lockIcon.addClass('fa-lock');
-            lockIcon.removeClass('fa-unlock');
-        }
-        else
-        {
-            lockIcon.addClass('fa-unlock');
-            lockIcon.removeClass('fa-lock');
-        }
+
+    _onBackgroundClick: function(e) {
+        if (!this.isMenuLocked && this.isMenuActive)
+            this._toggleWikiMenu();
     },
+
     _searchQueryFocused: function(e) {
-        this.isMenuActiveLocked = true;
         this.wikiMenu.toggleClass('wiki-menu-ext', true);
         this.wikiBody.toggleClass('wiki-search-underlayer', true);
     },
     _searchQueryBlurred: function(e) {
         this.wikiBody.toggleClass('wiki-search-underlayer', false);
         this.wikiMenu.toggleClass('wiki-menu-ext', false);
-        this.isMenuActiveLocked = false;
         if (this.searchPreviewList.is(':visible'))
             this.searchPreviewList.slideUp(200);
         if ($(document.activeElement).parents('#wiki-menu').length === 0)
--- a/wikked/templates/index.html	Tue Oct 16 22:08:51 2018 -0700
+++ b/wikked/templates/index.html	Thu Nov 01 21:25:23 2018 -0700
@@ -9,11 +9,11 @@
         {% block head %}{% endblock %}
     </head>
     <body>
-        <div id="app">
+        <div id="app" class="{%if nav.locked%}wiki-menu-active wiki-menu-locked{%endif%}">
             <div class="nav-wrapper">
                 {% block nav %}{% include 'nav.html' %}{% endblock %}
             </div>
-            <div class="wrapper{%if not nav.hide_menu%} wiki-menu-active{%endif%}{%if is_special_page%} special{%endif%}">
+            <div class="wrapper{%if is_special_page%} special{%endif%}">
                 {% block content %}{% endblock %}
             </div>
             <div class="footer-wrapper">
--- a/wikked/templates/nav.html	Tue Oct 16 22:08:51 2018 -0700
+++ b/wikked/templates/nav.html	Thu Nov 01 21:25:23 2018 -0700
@@ -1,9 +1,9 @@
 <a id="wiki-menu-shortcut" class="wiki-logo">
     <span>W</span>
 </a>
-<nav id="wiki-menu" role="navigation" class="pure-menu pure-menu-open{%if not nav.hide_menu%} wiki-menu-active{%endif%}">
-    <div id="wiki-menu-pin" title="Pin/unpin the wiki menu.">
-        <i class="fas fa-{%if not nav.hide_menu%}lock{%else%}unlock{%endif%}"></i>
+<nav id="wiki-menu" role="navigation" class="pure-menu pure-menu-open">
+    <div id="wiki-menu-header" title="Pin/unpin the wiki menu.">
+        <i id="wiki-menu-lock" class="fas fa-{{nav.lock_icon}}"></i>
     </div>
     <ul class="pure-menu-list">
         {%if nav.url_home%}<li class="pure-menu-item"><a href="{{nav.url_home}}"><i class="fas fa-home"></i> Home</a></li>{%endif%}
--- a/wikked/templates/special-nav.html	Tue Oct 16 22:08:51 2018 -0700
+++ b/wikked/templates/special-nav.html	Thu Nov 01 21:25:23 2018 -0700
@@ -1,9 +1,9 @@
 <a id="wiki-menu-shortcut" class="wiki-logo">
     <span>W</span>
 </a>
-<nav id="wiki-menu" role="navigation" class="pure-menu pure-menu-open{%if not nav.hide_menu%} wiki-menu-active{%endif%}">
-    <div id="wiki-menu-pin" title="Pin/unpin the wiki menu.">
-        <i class="fas fa-lock"></i>
+<nav id="wiki-menu" role="navigation" class="pure-menu pure-menu-open">
+    <div id="wiki-menu-header" title="Pin/unpin the wiki menu.">
+        <i id="wiki-menu-lock" class="fas fa-{{nav.lock_icon}}"></i>
     </div>
     <ul class="pure-menu-list">
         <li class="pure-menu-item"><a href="/"><i class="fas fa-home"></i> Home</a></li>
--- a/wikked/views/__init__.py	Tue Oct 16 22:08:51 2018 -0700
+++ b/wikked/views/__init__.py	Thu Nov 01 21:25:23 2018 -0700
@@ -39,8 +39,9 @@
 
     nav = {'extras': [], 'footers': []}
 
-    nav['hide_menu'] = (
-        request.cookies.get('wiki-hide-nav') == '1')
+    nav_locked = request.cookies.get('wiki-nav-locked')
+    nav['locked'] = (nav_locked == '1')
+    nav['lock_icon'] = 'lock' if nav['locked'] else 'unlock'
 
     nav['url_help'] = url_for('read', url='help:/Help Contents')