Modular menu on non-modular pages

@pgrav

Desirability:
I wonder if this is something I would use in my projects, because I think this will create a less than optimal user experience.

The regular pages probably show a nice header and title for context, while when navigating to child modules the user finds himself midway a page without header and context. I think this behaviour is not consistent and hence confusing. Besides, why using a modular page if you present the child pages as being separate content already?

I haven’t used modular pages in my themes (yet) and I think I would use them as follows:

  • As the only page for a single page website:
    The ‘onpage_menu: true’ would make it easy for users to jump to sections. It feels natural to the user.
  • For multi-page website:
    I would switch off the ‘onpage_menu’ and show the page as a single regular page.

Solution using Quark theme:
Steps: (Skip to code below if not interested in process/explaination…)

  • In ‘modular.md’ set ‘onpage_menu: false’
    The modular page will now use ‘partials/navigation.html.twig’ to generate the menu containing ‘Home Page1 page2’.
  • Combine part of ‘modular.html.twig’ navigation with ‘partials/navigation.html.twig’ and use “page.tempate == ‘modular’” to discriminated between the page types.
  • Construct the anchor urls for the modular children by combining the url of the modular page and the menu of the child module: href="{{p.url}}/#{{ _self.pageLinkName(module.menu) }}"
  • The menu will now show: ‘Home Module1 Module2 Page1 Page2’
  • Unfortunately, the smooth scrolling and menu highlighting has disappeared from the modular page. This is because the required javascript is only run with ‘onpage_menu=true’.
  • Fix:
    • In ‘modular.html.twig’, remove the surrounding if-statements in {% block javascripts %} and {% block bottom %} to add the required javascripts.
    • In ‘navigation.html.twig’ add class ‘navigation’ to the ‘<ul>’
  • But now, because of the enabled javascript, we cannot navigate to ‘Page1’ and ‘Page2’ anymore… Sigh…
  • Fix:
    • Add class ‘regular’ to all menu-items of regular pages in ‘navigation.html.twig’.
    • Tell the javascript in ‘modular.html.twig’ to exclude the menuitems with class ‘regular’ by setting its filter to filter: ':not(.external):not(.regular)'

It should work now…

Code:
‘modular.html.twig’:

{% extends 'partials/base.html.twig' %}

{% set show_onpage_menu = header.onpage_menu == true or header.onpage_menu is null %}
{% macro pageLinkName(text) %}{{ text|lower|replace({' ':'_'}) }}{% endmacro %}

{% block javascripts %}
    {# {% if show_onpage_menu %} #}                  {# Comment out #}
        {% do assets.add('theme://js/singlepagenav.min.js') %}
    {# {% endif %} #}                                {# Comment out #}
    {{ parent() }}
{% endblock %}

{% block bottom %}
    {{ parent() }}
    {# {% if show_onpage_menu %} #}                   {# Comment out #}
        <script>
        // singlePageNav initialization & configuration
        $('ul.navigation').singlePageNav({
            offset: $('#header').outerHeight(),
            filter: ':not(.external):not(.regular)',   // Add filter
            updateHash: true,
            currentClass: 'active'
        });
        </script>
    {# {% endif %} #}                                 {# Comment out #}
{% endblock %}

{% block header_navigation %}
    {% if show_onpage_menu %}
        <ul class="navigation">
        {% for module in page.collection() %}
            {% set current_module = (module.active or module.activeChild) ? 'active' : '' %}
            <li><a class="{{ current_module }}" href="#{{ _self.pageLinkName(module.menu) }}">{{ module.menu }}</a></li>
        {% endfor %}
        {% for mitem in site.menu %}
            <li>
                <a {% if mitem.class %}class="{{ mitem.class }}"{% endif %} href="{{ mitem.url }}">
                    {% if mitem.icon %}<i class="fa fa-{{ mitem.icon }}"></i>{% endif %}
                    {{ mitem.text }}
                </a>
            </li>
        {% endfor %}
        </ul>
    {% else %}
        {{  parent() }}
    {% endif %}
{% endblock %}

{% block hero %}
    {% for module in page.collection() if module.template == 'modular/hero' %}
        <div id="{{ _self.pageLinkName(module.menu) }}"></div>
        {{ module.content }}
    {% endfor %}
{% endblock %}

{% block body %}
    {% for module in page.collection() if module.template != 'modular/hero' %}
        <div id="{{ _self.pageLinkName(module.menu) }}"></div>
        {{ module.content }}
    {% endfor %}
{% endblock %}

‘/partials/navigation.html.twig’:

{% macro pageLinkName(text) %}{{ text|lower|replace({' ':'_'}) }}{% endmacro %}

{% macro nav_loop(page) %}
    {% for p in page.children.visible %}
        {% if p.template != 'modular' %}            {# Add if #}
            {% set active_page = (p.active or p.activeChild) ? 'active' : '' %}
            {% if p.children.visible.count > 0 %}
                <li>
                    <a href="{{ p.url }}" class="regular {{ active_page }}">    {# Add class 'regular' #}
                        {{ p.menu }}
                    </a>
                    <ul>
                        {{ _self.nav_loop(p) }}
                    </ul>
                </li>
            {% else %}
                <li>
                    <a href="{{ p.url }}" class="regular {{ active_page }}">    {# Add class 'regular' #}
                        {{ p.menu }}
                    </a>
                </li>
            {% endif %}
        {% else %}                                   {# Add code to loop through modules #}
            {% for module in p.collection() %}
                {% set current_module = (module.active or module.activeChild) ? 'active' : '' %}
                <li><a class="{{ current_module }}" href="{{p.url}}/#{{ _self.pageLinkName(module.menu) }}">{{ module.menu }}</a></li>
            {% endfor %}
        {% endif %}
    {% endfor %}
{% endmacro %}

<ul {{ tree ? 'class="navigation tree"' : 'class="navigation"' }}>    {# Add class 'navigation' required by javascript #}
    {{ _self.nav_loop(pages) }}
</ul>