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.
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, ..."
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.
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
J'ai écrit un simple plugin Jekyll pour résoudre ce problème:
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)
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.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>
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>
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
---
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.
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é.
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 %}