web-dev-qa-db-fra.com

Menu de navigation trié avec Jekyll et Liquid

Je construis un site statique (pas de blog) avec Jekyll/Liquid. Je veux qu'il ait un menu de navigation généré automatiquement qui répertorie toutes les pages existantes et met en évidence la page actuelle. Les éléments doivent être ajoutés au menu dans un ordre particulier. Par conséquent, je définis une propriété weight dans le YAML des pages:

---
layout : default
title  : Some title
weight : 5
---

Le menu de navigation est construit comme suit:

<ul>
  {% for p in site.pages | sort:weight %}
    <li>
      <a {% if p.url == page.url %}class="active"{% endif %} href="{{ p.url }}">
        {{ p.title }}
      </a>
    </li>
  {% endfor %}
</ul>

Cela crée des liens vers toutes les pages existantes, mais ils ne sont pas triés, le filtre sort semble être ignoré. Évidemment, je fais quelque chose de mal, mais je ne peux pas comprendre quoi.

68
flyx

Depuis Jekyll 2.2.0, vous pouvez trier un tableau d'objets par n'importe quelle propriété d'objet. Vous pouvez désormais:

{% assign pages = site.pages | sort:"weight"  %}
<ul>
  {% for p in pages %}
    <li>
      <a {% if p.url == page.url %}class="active"{% endif %} href="{{ p.url }}">
        {{ p.title }}
      </a>
    </li>
  {% endfor %}
</ul>

Et économisez beaucoup de temps de construction par rapport à la solution @kikito.

modifier : Vous [~ # ~] devez [~ # ~] attribuez votre propriété de tri sous forme d'entier weight: 10 et non comme une chaîne weight: "10".

L'affectation de propriétés de tri sous forme de chaîne se termine par un tri de chaîne comme "1, 10, 11, 2, 20, ..."

74
David Jacquel

Votre seule option semble utiliser une double boucle.

<ul>
{% for weight in (1..10) %}
  {% for p in site.pages %}
    {% if p.weight == weight %}
      <li>
        <a {% if p.url == page.url %}class="active"{% endif %} href="{{ p.url }}">
          {{ p.title }}
        </a>
      </li>
    {% endif %}
  {% endfor %}
{% endfor %}
</ul>

Aussi laid que cela soit, cela devrait fonctionner. Si vous avez également des pages sans poids, vous devrez inclure une boucle interne supplémentaire en faisant simplement {% unless p.weight %} avant/après l'actuel interne.

36
kikito

La solution ci-dessous fonctionne sur Github (ne nécessite pas de plugin):

{% assign sorted_pages = site.pages | sort:"name" %}
{% for node in sorted_pages %}
  <li><a href="{{node.url}}">{{node.title}}</a></li>
{% endfor %}

L'extrait ci-dessus trie les pages par nom de fichier (l'attribut name sur l'objet Page est dérivé du nom de fichier). J'ai renommé les fichiers pour qu'ils correspondent à ma commande: 00-index.md, 01-about.md - et hop! Les pages sont ordonnées.

Un problème est que ces préfixes numériques se retrouvent dans les URL, ce qui semble gênant pour la plupart des pages et est un vrai problème avec 00-index.html. Permalilnks à la rescousse:

---
layout: default
title: News
permalink: "index.html"
---

P.S. Je voulais être intelligent et ajouter des attributs personnalisés uniquement pour le tri. Malheureusement, les attributs personnalisés ne sont pas accessibles en tant que méthodes sur la classe Page et ne peuvent donc pas être utilisés pour le tri:

{% assign sorted_pages = site.pages | sort:"weight" %} #bummer
29

J'ai écrit un simple plugin Jekyll pour résoudre ce problème:

  1. Copie sorted_for.rb de https://Gist.github.com/3765912 à _plugins sous-répertoire de votre projet Jekyll:

    module Jekyll
      class SortedForTag < Liquid::For
        def render(context)
          sorted_collection = context[@collection_name].dup
          sorted_collection.sort_by! { |i| i.to_liquid[@attributes['sort_by']] }
    
          sorted_collection_name = "#{@collection_name}_sorted".sub('.', '_')
          context[sorted_collection_name] = sorted_collection
          @collection_name = sorted_collection_name
    
          super
        end
    
        def end_tag
          'endsorted_for'
        end
      end
    end
    
    Liquid::Template.register_tag('sorted_for', Jekyll::SortedForTag)
    
  2. Utilisez la balise sorted_for au lieu de for avec sort_by:property paramètre pour trier par propriété donnée. Vous pouvez également ajouter reversed comme le for d'origine.
  3. N'oubliez pas d'utiliser une balise de fin différente endsorted_for.

Dans votre cas, l'utilisation ressemble à ceci:

<ul>
  {% sorted_for p in site.pages sort_by:weight %}
    <li>
      <a {% if p.url == page.url %}class="active"{% endif %} href="{{ p.url }}">
        {{ p.title }}
      </a>
    </li>
  {% endsorted_for %}
</ul>
15
Jan Dupal

Solution simple:

Attribuer un tableau trié de site.pages commencez par exécuter une boucle for sur le tableau.

Votre code ressemblera à:

{% assign links = site.pages | sort: 'weight' %}
{% for p in links %}
  <li>
    <a {% if p.url == page.url %}class="active"{% endif %} href="{{ p.url }}">
      {{ p.title }}
    </a>
  </li>
{% endfor %}

Cela fonctionne dans ma barre de navigation _include qui est simplement:

<section id="navbar">
    <nav>
        {% assign tabs = site.pages | sort: 'weight' %}
        {% for p in tabs %}
            <span class="navitem"><a href="{{ p.url }}">{{ p.title }}</a></span>
        {% endfor %}
    </nav>
</section>
10
sdmeyers

La solution la plus simple serait de préfixer le nom de fichier de vos pages avec un index comme celui-ci:

00-home.html 01-services.html 02-page3.html

Les pages sont classées par nom de fichier. Cependant, vous aurez maintenant des URL moches.

Dans vos sections avant-sujet yaml, vous pouvez remplacer l'URL générée en définissant la variable de permalien.

Par exemple:

---
layout: default
permalink: index.html
---
10
Mark Meeus

J'ai résolu cela en utilisant un générateur. Le générateur parcourt les pages, récupère les données de navigation, les trie et les repousse dans la configuration du site. De là, Liquid peut récupérer les données et les afficher. Il prend également soin de cacher et de montrer les objets.

Considérez ce fragment de page:

---
navigation:
  title: Page name
  weight: 100
  show: true
---
content.

La navigation est rendue avec ce fragment Liquid:

{% for p in site.navigation %}
<li> 
    <a  {% if p.url == page.url %}class="active"{% endif %} href="{{ p.url }}">{{ p.navigation.title }}</a>
</li>
{% endfor %}

Placez le code suivant dans un fichier de votre dossier _plugins:

module Jekyll

  class SiteNavigation < Jekyll::Generator
    safe true
    priority :lowest

    def generate(site)

        # First remove all invisible items (default: nil = show in nav)
        sorted = []
        site.pages.each do |page|
          sorted << page if page.data["navigation"]["show"] != false
        end

        # Then sort em according to weight
        sorted = sorted.sort{ |a,b| a.data["navigation"]["weight"] <=> b.data["navigation"]["weight"] } 

        # Debug info.
        puts "Sorted resulting navigation:  (use site.config['sorted_navigation']) "
        sorted.each do |p|
          puts p.inspect 
        end

        # Access this in Liquid using: site.navigation
        site.config["navigation"] = sorted
    end
  end
end

J'ai passé un bon moment à comprendre cela depuis que je suis assez nouveau pour Jekyll et Ruby, donc ce serait génial si quelqu'un pouvait s'améliorer.

5
kevin

Je peux faire fonctionner le code ci-dessous avec Jekyll/Liquid correspondant à vos besoins avec la catégorie:

  • crée des liens vers toutes les pages existantes,
  • trié par poids (fonctionne également sur le tri par catégorie),
  • mettez en surbrillance la page actuelle.

En plus d'eux, il indique également le nombre de messages. Tout se fait sans plug-in.

<ul class="topics">
{% capture tags %}
    {% for tag in site.categories %}
        {{ tag[0] }}
    {% endfor %}
{% endcapture %}
{% assign sortedtags = tags | split:' ' | sort %}
    {% for tag in sortedtags %}
    <li class="topic-header"><b>{{ tag }} ({{ site.categories[tag] | size }} topics)</b>
        <ul class='subnavlist'>
        {% assign posts = site.categories[tag] | sort:"weight" %}
        {% for post in posts %}
            <li class='recipe {% if post.url == page.url %}active{% endif %}'>
            <a href="/{{ site.github.project_title }}{{ post.url }}">{{ post.title }}</a>
            </li>
        {% endfor %}
        </ul>
    </li>
    {% endfor %}
</ul>

Vérifiez-le sur l'action sur notre page de réseautage. Vous pouvez cliquer sur un post pour mettre en surbrillance la navigation, ainsi qu'un lien donné pour vous amener à la page source où leur poids est attribué.

1
Chetabahana

Si vous essayez de trier par poids et par étiquette et de limiter le nombre à 10, voici le code pour le faire:

{% assign counter = '0' %}
{% assign pages = site.pages | sort: "weight"  %}
{% for page in pages %}
{% for tag in page.tags %}
{% if tag == "Getting Started" and counter < '9' %}
{% capture counter %}{{ counter | plus:'1' }}{% endcapture %}
<li><a href="{{ page.permalink | prepend: site.baseurl }}">{{page.title}}</a></li>
{% endif %}
{% endfor %}
{% endfor %} 
0
Tom Johnson