Modular menu on non-modular pages

Hi i’m lost…
I want to show the modular menu on a non-modular page
The file structure is

- 01.home
   _module1
   _module2
- page1
- page2

on the pages (page1, page2) i want to show the menu to get back to _module1, _module2

If have set onpage_menu: true so on the modular-page i see the navigation menu

module1 module2 

but not on the pages. So i cant go back over the navigation menu

{% if not page.home() %}
{% for page in pages.children %}		
   {% for module in page.collection() %}
      <li class="nav-item"><a href="#{{ _self.pageLinkName(module.menu) }}" class="nav-link">{{ module.menu }}</a></li>
   {% endfor %}
{% endfor %}
{% endif %}

brings me near but the URL is:

http://example.com/page1#

How can i get rid of the page1 in the URL and get the modules so that the link is

http://example.com/#module1

Can somebody give me a hint how to do this
https://discourse.getgrav.org/t/acces-modular-parent-from-modular/1036
and other things i tried didn’t help me

Thanks in advance!

@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>

Wow :grinning: At first pamtbaau thank you very much for giving this answer in such a detailed way and with this hints, tips and explanation. i appreciate that very much!!! and sorry for the delay in reply.

To the navigation: It is a Onepage-website. The 2 pages that a non-modular, are pages that the user “normally” dont uses, and they sit in the footer (not the main navigation) because they have to be there by law (impressum,privacy statement). So i think there is no problem with not consistent/confusing user experience.

and that is as well the reason why i dont wont a menu

Home Module1 Module2 Page1 Page2

do you (or anybody else) see a way to get the onpage_menu on the non-modular pages (=page1, page2) so that i can jump back to the main onepage site like

Home Module1 Module2

my workround for the moment is

{# menu for non modulare pages#}
{% if not page.home() %}
   {% for page in pages.children %}
      {% if page.visible %} 
		<li class= "backhome">
			<a href="{{ page.url }}">
		           back to home
			</a>
		</li>
	{% endif %}
	{% endfor %}
{% endif %}

so that i get a menu on the non-modular pages

back to home 

but that is not the best user experience

Thanks

in addition to the text before:

{% if not page.home() %}
   {% for page in pages.children %}		
	 {% for module in page.collection() %}
	<li class="nav-item"><a href="{{page.url}}/#{{ (module.menu) }}" class="nav-link">{{ module.menu }}</a></li>
	{% endfor %}
  {% endfor %}
{% endif %}

gives me what i want

Home Module1 Module2

although i dont no if this is the best/correct way??

1 Like

@pgrav Wished I had understood your requirements a little bit better the first time… :slight_smile:

I find it hard to judge whether there is a better or more correct way, while I only see fragments of the code without the total picture.

Nonetheless, a suggestion I have is to make it a little bit less error prone in case the menu’s of the modules might contain uppercase characters and/or spaces…

You might want to add the following macro to the twig file:

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

and use the following code to generate the anchor:

<li class="nav-item"><a href="{{page.url}}/#{{ _self.pageLinkName(module.menu) }}" class="nav-link">{{ module.menu }}</a></li>
1 Like

@anon76427325 thanks again
it works perfect (beside the problem with anker an german umlaute) but thats ok.
:slightly_smiling_face: pgrav

1 Like

@anon76427325
Thanks for your explanations. I have another problem with the code you gave, when I click on a drop down menu item, the black menu doesn’t close. Do you have the solution?

Hi Filou,
i used

$(“.navbar-nav>li>a”).on(“click”, function () {
$(“.navbar-collapse”).collapse(“hide”);
})
in the site.js for this