clayh53 / tufte-jekyll

Minimal Jekyll blog styled to resemble the look and layout of Edward Tufte's books
MIT License
635 stars 206 forks source link

Collapsible navbar #40

Open ekstroem opened 8 years ago

ekstroem commented 8 years ago

This is not a bug but more like a feature/enhancement request. I'm still trying to tweak my pages and have run into this minor issue:

I'd like to have a collapsible navbar.

Currently the navigation bar is created from the site.pages and while the tex size scales with device/media size it is not uncommon to get something that is wider that a single line if there are more than a few pages in the menu.

If the text width becomes too large then I'd like either all the menu items (besides the site name) to collapse or just the ones that there aren't room for.

For starters I moved the navigation part to a separate file _includes/nav.html (shown below)

<header>
<nav id="menu">
<ul>
<li><a href="{{site.baseurl}}/">sitename</a></li>
{% for node in site.pages %}{% unless node.nav_exclude %}{% if page.url == node.url %}
<li><a class="active" href="{{node.url | prepend: site.baseurl}}">{{node.title}}</a> </li>
{% else %}
<li><a href="{{node.url | prepend: site.baseurl}}">{{node.title}}</a></li>
{% endif %}{% endunless %}{% endfor %}
</ul>
</nav>
</header>

where the menu items are items in an unordered list. Now I found some previous code to work as a collapsible navbar. Here's the part of the script that does all the computation with the width of the menu bar entries and moves them back and forth between being hidden (included as part of the footer).

/*--------------------------------------------------
Hidden Nav
--------------------------------------------------*/
hiddenNavBar = {
    $menu: $('#menu'),
    init: function () {
        this.resize();
        $('<div id="on-hidden-menu"><div class="toggle"><span></span></div><ul></ul></div>').hide().insertAfter(this.$menu);
        // toggle
        $('#on-hidden-menu .toggle').click(function () {
                                                  $('#on-hidden-menu').toggleClass('open');
                                              });

        // win load & resize
        $(window).on('load resize', function () {
                         hiddenNavBar.resize();
                     });
    },
    resize: function () {
        setTimeout(function () {
                          var menuWidth = $('ul', this.$menu).width() + 60;
                          var winW = $(window).width();

                          console.log(menuWidth, winW);

                          if (menuWidth > winW) {
                              console.log('init');

                              $('#on-hidden-menu').show();
/*                            $clone = $('li:not(".on-hidden"):last', this.$menu).addClass('on-hidden').clone(); */
                              $clone = $('#menu li:not(".on-hidden"):last', this.$menu).addClass('on-hidden').clone();
                              if ($clone.parent().size() == 0) {
                                  $clone.prependTo($('#on-hidden-menu ul'));
                              }

                              hiddenNavBar.resize();
                              /** this.menu */
                          } else if (menuWidth + $('li.on-hidden:first').width() < winW) {
                              $('li.on-hidden:first').removeClass('on-hidden');
                              $('#on-hidden-menu ul li:first').remove();
                          }

                          if ($('.on-hidden').size() == 0) {
                              $('#on-hidden-menu').removeClass('open').hide();
                          }
                      }, 10);
    }
};

/*--------------------------------------------------
DOC READY
--------------------------------------------------*/
$(function () {
         hiddenNavBar.init();
     })

and then there's the corresponding css file information (included in the header).

/*--------------------------------------------------
Nav
--------------------------------------------------*/

header {
padding: 15px 5px;
position: relative;
z-index: 1;
}

body.full-width > header {
}

#menu {
white-space:nowrap;
position: relative;
z-index: 1;
width: auto;
}

#menu ul {
list-style: none;
list-style-type: none;
margin: 0;
padding: 0;
white-space: nowrap;
display: inline-block;
}

#menu ul li {
display: inline-block;
position: relative;
}

#menu ul li a {
text-decoration: none;
padding: 0.7em;
}

/*--------------------------------------------------
On Hidden Menu
--------------------------------------------------*/

#menu ul li.on-hidden { display: none; }

#on-hidden-menu {
display: block;
position: absolute;
z-index: 10;
right: 0;
margin-top: 15px;
min-width: 280px;
}

#on-hidden-menu ul {
margin: 0;
padding: 0;
list-style: none;
position: relative;
overflow: hidden;
height: 0;
}

#on-hidden-menu li {
background: #30424d;
border-bottom: 1px solid #273640;
opacity: 0;
-moz-transition: all .4s ease-in-out .2s;
-o-transition: all .4s ease-in-out .2s;
-webkit-transition: all .4s ease-in-out .2s;
transition: all .4s ease-in-out .2s;
position: relative;
}

#on-hidden-menu li a {
color: rgba(255,255,255,.9);
text-decoration: none;
padding: 10px 15px;
display: block;
}

#on-hidden-menu li a:hover { background: #354C5A; }

/* on hidden menu open */

#on-hidden-menu.open ul {
display: block;
height: 100%;
}

#on-hidden-menu.open ul li {
    opacity: 1;
}

#on-hidden-menu.open ul li:last-child {
    border-bottom-left-radius: 5px;
}

/* toggle */

#on-hidden-menu .toggle {
width: 32px;
position: absolute;
top: -42px;
right: 10px;
height: 32px;
background-color: #f73a14;
z-index: 1;
cursor: pointer;
border-radius: 2px;
}

#on-hidden-menu .toggle:before, #on-hidden-menu .toggle:after,
#on-hidden-menu .toggle span:before {
content: '';
width: 4px;
height: 4px;
background: #fff;
border-radius: 5px;
position: absolute;
top: 17px;
left: 5px;
-moz-transition: all .4s ease-in-out;
-o-transition: all .4s ease-in-out;
-webkit-transition: all .4s ease-in-out;
transition: all .4s ease-in-out;
}

#on-hidden-menu .toggle:after {
left: 13px;
-moz-transition-delay: .1s;
-o-transition-delay: .1s;
-webkit-transition-delay: .1s;
transition-delay: .1s;
}

#on-hidden-menu .toggle span:before {
left: 21px;
-moz-transition-delay: .2s;
-o-transition-delay: .2s;
-webkit-transition-delay: .2s;
transition-delay: .2s;
}

/* close */

#on-hidden-menu.open .toggle:before, #on-hidden-menu.open .toggle:after {
width: 20px;
-moz-transform: rotate(225deg);
-ms-transform: rotate(225deg);
-o-transform: rotate(225deg);
-webkit-transform: rotate(225deg);
transform: rotate(225deg);
top: 14px;
height: 3px;
}

#on-hidden-menu.open .toggle:after {
-moz-transform: rotate(-225deg);
-ms-transform: rotate(-225deg);
-o-transform: rotate(-225deg);
-webkit-transform: rotate(-225deg);
transform: rotate(-225deg);
left: 5px;
-moz-transition-delay: .0s;
-o-transition-delay: .0s;
-webkit-transition-delay: .0s;
transition-delay: .0s;
}

#on-hidden-menu.open .toggle span:before {
top: 14px;
left: 13px;
width: 2px;
height: 2px;
-moz-transition-delay: .0s;
-o-transition-delay: .0s;
-webkit-transition-delay: .0s;
transition-delay: .0s;
}

Okay. So far so good. Then I want to fix the nav.html so it matches the collapsible code (forget about the aesthetics here for now - it's not a beauty but that could be fixed). I add the ID's to nav.html

<header>
<nav id="menu">
<ul id="menu">
<li><a href="{{site.baseurl}}/">sandsynlig<b>vis</b>.dk</a></li>
{% for node in site.pages %}{% unless node.nav_exclude %}{% if page.url == node.url %}
<li><a class="active"  id="menu" href="{{node.url | prepend: site.baseurl}}">{{node.title}}</a> </li>
{% else %}
<li><a id="menu" href="{{node.url | prepend: site.baseurl}}">{{node.title}}</a></li>
{% endif %}{% endunless %}{% endfor %}
</ul>
</nav>
</header>

which makes the collapsible navbar function. Sort or anyway. The width calculation is not working perfectly and the menu item pops in and out of existence until there's two items in the hidden part of the menu. Can anyone help with this and/or would help make it blend in with the rest of the Tufte-CSS format?

I can set up a (version) of the page so you can see what is wrong, but I haven't pushed it to the official server since it isn't working.

ekstroem commented 8 years ago

Okay. I did a bit of tweaking and seems to have it almost working. You can see a working example here. There's still a few corrections to be made to make it blend in completely but it's somewhat acceptable as it is.

I can write it up in case anyone else would be of interest.

clayh53 commented 8 years ago

I haven't had time to look at this, but at first glance this seems like a good idea, particularly for the smaller device width use cases. If it can be easily added I will add it to the repo.

ekstroem commented 8 years ago

Want me to try to extract the necessary bits and put them into a pull request?

clayh53 commented 8 years ago

That would be great if it wont chew up too much of your time.

Thanks

Sent using 100% all-natural biodynamic electrons

On Apr 4, 2016, at 7:17 PM, Claus Ekstrøm notifications@github.com wrote:

Want me to try to extract the necessary bits and put them into a pull request?

— You are receiving this because you commented. Reply to this email directly or view it on GitHub