Статьи

Полностью функциональный блог Jekyll

Блог (блог). Красное слово на белом фоне

Наступает время, когда учебников по началу работы недостаточно. Это не один из тех уроков. После этой статьи у вас будет возможность создать полностью функциональный блог Jekyll с возможностями разбивки на страницы и поиска. Будьте готовы, чтобы увидеть, насколько удивительным может быть Джекилл .

Аудитория

Это для:

  • Люди, которые имеют базовые знания о Jekyll (Примечание: если вы не читаете документы. Легко добраться до базовых.)
  • Знать, как использовать текстовый редактор
  • Можно сделать gem install
  • Очень хороши в HTML и JavaScript
  • Понимание жидких шаблонов (Опять же… смотрите документы, если нет)

Ресурсы

Если в какой-то момент вы потерялись или запутались, эти ссылки должны помочь вам:

Идти!

Чтобы убедиться, что мы все на одной странице, я собираюсь использовать Jekyll версии 2.5.3. Так что, если вы еще этого не сделали, вам следует gem install jekyll -v 2.5.3 .

Мы не будем использовать команду jekyll new для создания этого блога. Это отлично подходит для людей, которые хотят почувствовать блог Jekyll, но я чувствую, что это отвлекает от обучения. Вместо этого давайте начнем с создания свежего git-репозитория и добавления в него файла config.yml . Это config.yml , где все настройки сайта идут. Переменные в этом файле могут быть доступны с помощью глобальной переменной site (например, site.foo ).

 $ mkdir jekyll-blog $ cd jekyll-blog $ git init $ git checkout -b gh-pages # for GitHub pages support $ echo "2.2.2"; > .ruby-version # sets Ruby version $ touch _config.yml 

Файл YAML:

  

Теперь немного, чтобы убедиться, что мы начинаем правильно:

 $ git add . $ git commit -m "Initial blog configuration" $ git push -u origin gh-pages # you should create a GitHub repo if you haven't yet 

Классная вещь. Вместо того, чтобы наша master ветвь была нашей ветвью развертывания, gh-pages будет выполнять эту роль.

Прежде чем мы начнем, давайте посмотрим, что мы хотим в нашем блоге:

  • Индексная страница постов
  • Страница для отдельных сообщений
  • Возможность поиска постов

Нам понадобится несколько реальных постов для тестирования, поэтому я сгенерировал несколько с помощью генератора Lorem Ipsum. Для вашего удобства вы можете получить их здесь. Поместите их в каталог с именем _posts .

Каждая страница в Jekyll нуждается в шаблоне по умолчанию, поэтому создайте его перед созданием страницы индекса. Это избавляет нас от необходимости писать все обязательные материал:

 $ mkdir _layouts $ touch _layouts/default.html 

И HTML:

 # _layouts/default.html <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>{% if page.title %}{{ page.title }} &&middot; {% endif %}{{ site.title }}</title> {% include libs.html %} </head> <body> {{ content }} </body> </html> 

В теге title вы заметите, что мы использовали оператор if :

 {% if page.title %}{{ page.title }} &&middot; {% endif %} 

Это гласит: если переменная страницы, title определена, то визуализируйте ее вместе с разделителем. Если нет, то ничего не будет показано.

Мы также использовали тег include liquid для извлечения внешнего HTML-файла с именем libs.html, который находится в каталоге _include и содержит наши библиотеки. Можно разделить каждый шаблон на более мелкие, но в определенный момент он занимает больше времени, чем стоит.

 # _includes/libs.html <!-- Stylesheets --> <link href='//fonts.googleapis.com/css?family=Arvo:400,400italic,700' rel='stylesheet' type='text/css'> <link href="{{ '/css/style.css' | prepend: site.baseurl }}"> <!-- JS --> <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script> <script src="{{ '/js/app.js' | prepend: site.baseurl }}"></script> 

Потрясающие. Обратите внимание, что мы использовали жидкостный фильтр prepend для добавления предварительно определенного базового URL нашего сайта. Он определен как /blog/ поэтому ресурсы загружаются правильно, если сайт размещен по URL-адресу, например http://johndoe.github.io/blog/ . Это полезно, потому что наш макет по умолчанию будет применяться ко всем страницам.

Теперь давайте сделаем страницу индекса.

Страница индекса должна отображать целые сообщения и разбивать их на каждые 3 сообщения (у нас есть 4). Также на нем должны быть ссылки на отдельные страницы сообщений. Джекилл делает это очень легко.

 # index.html --- title: Home layout: default --- <h1>{{ site.author }}'s Blog</h1> <section class="posts"> {% for post in site.posts %} <li><date>{{ post.date | date: "%B %-d, %Y"}}<a href="{{ post.url | prepend: site.baseurl }}">{{ post.title }} {% endfor %} </section> 

Это просто и просто индексная страница с классическим for..in над сообщениями.

Поиск

Директива AngularJS ng-repeat идеально подходит для быстрого поиска записей в реальном времени. Но сначала нам нужен какой-то API для Angular. Джекилл может сделать это для нас в чистой жидкости. Поскольку сайт генерируется статически, данные в нашем «API» также не должны генерироваться динамически. Итак, чтобы сгенерировать API, просто используйте следующий код:

 # posts.json --- layout: null --- { "posts": [ {% for post in site.posts %}{ "title": "{{ post.title }}", "url": "{{ post.url | prepend: site.baseurl }}", "date": "{{ post.date | date: "%B %-d, %Y" }}", "raw_date": "{{ post.date }}" }{% unless forloop.last %},{% endunless %} {% endfor %} ] } 

Это довольно просто и генерирует хороший API для нашего блога, который выглядит примерно так:

 { "posts": [ { "title": "Sample 4", "url": "/2015/05/20/Sample-4.html", "date": "May 20, 2015", "raw_date": "2015-05-20 00:00:00 -0400" }, { "title": "Sample 3", "url": "/2015/05/18/Sample-3.html", "date": "May 18, 2015", "raw_date": "2015-05-18 00:00:00 -0400" }, { "title": "Sample 1", "url": "/2015/05/17/Sample-1.html", "date": "May 17, 2015", "raw_date": "2015-05-17 00:00:00 -0400" }, { "title": "Sample 2", "url": "/2015/05/15/Sample-2.html", "date": "May 15, 2015", "raw_date": "2015-05-15 00:00:00 -0400" } ] } 

Так, как мы используем это в нашем блоге, чтобы добавить функциональность поиска?

 # js/app.js angular.module('JekyllBlog', []) .controller('SearchCtrl', ['$scope', '$http', function($scope, $http) { $http.get('/posts.json').success(function(data) { $scope.posts = data.posts; }); }]); 

Теперь добавьте это на страницу индекса, но есть проблема: Jekyll проанализирует скобки AngularJS.

 <p>{{wow.something}}</p> <!-- is parsed into... --> <p></p> 

Это потому, что Jekyll запускает все шаблоны через Liquid, что предполагает (как и должно быть), что все скобки являются частью шаблонов Liquid. Итак, мы должны обойти это. Одним из вариантов является этот плагин, который я написал, но поскольку мы планируем развертывание на страницах GitHub, пользовательские плагины не являются опцией. Придется использовать теги {% raw %} Liquid (поверьте мне, не так весело).

 # index.html <div class="posts" ng-controller="SearchCtrl"> <input type="search" class="search" ng-model="query"> <ul> <li ng-repeat="post in posts | filter:query "> <date ng-bind="post.date"></date> <a href="{% raw %}{{ post.url }}{% endraw %}" ng-bind="post.title"></a> </li> </ul> </div> 

Особый соус здесь - это сочетание ng-repeat и filter . Мы в основном говорим Angular отображать каждый элемент в массиве posts (с псевдонимом post ), который соответствует переменной области query . Вы заметите, что в верхней части списка мы добавили поисковый ввод, связанный с помощью ng-model в переменную области query . Затем мы просто повторно используем тот же вывод, который использовался ранее в {% for post in posts %} , но используя Jekyll «API».

А как насчет людей, которые не имеют JS?

Если вам действительно нужно угождать тем людям, у которых не включен JavaScript, вы можете использовать немного магии ng-cloak .

 # css/styles.css (as recommended by: https://docs.angularjs.org/api/ng/directive/ngCloak) [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak { display: none !important; } 
 # index.html <div ng-cloak class="posts" ng-controller="SearchCtrl"> <input type="search" class="search" ng-model="query"> <ul> <li ng-repeat="post in posts | filter:query "> <date ng-bind="post.date"></date> <a href="{% raw %}{{ post.url }}{% endraw %}" ng-bind="post.title"></a> </li> </ul> </div> <div ng-show class="posts"> <ul> {% for post in posts %} <li><date>{{ post.date | date: "%B %-d, %Y"}}<a href="{{ post.url | prepend: site.baseurl }}">{{ post.title }}</a></li> {% endfor %} </ul> </div> 

Это работает через некоторую интересную логику. Во-первых, директива AngularJS ' ng-cloak обнаруживается некоторыми стилями CSS и скрыта до загрузки AngularJS. Таким образом, если JS отключен, ничего не отображается.

Затем директива ng-show добавляется в сгенерированный Jekyll список сообщений. Это работает, потому что AngularJS по умолчанию ng-show значение false , что означает, что список Jekyll будет отображаться только в том случае, если AngularJS не загружен.

А как насчет сообщений?

У каждого поста есть ссылка, но мы на самом деле не говорили о том, что происходит, когда вы нажимаете эту ссылку. Прямо сейчас он отображает разметку поста, отображаемую в HTML, но мы хотим большего. Во-первых, давайте добавим макет по умолчанию для всех наших постов, потому что нам не нужно беспокоиться об этом при написании нового поста:

 # _config.yml ... other config ... defaults: - scope: path: "" type: "posts" values: layout: "post" по # _config.yml ... other config ... defaults: - scope: path: "" type: "posts" values: layout: "post" 

Это означает, что layout: post будет добавлен во все файлы типа post . Теперь нам нужно создать этот макет поста:

 $ touch _layouts/post.html 

Этот макет действительно нуждается только в заголовке и месте для отображения поста:

 # _layouts/post.html --> <article> <h2>{{ page.title }}</h2> <small>Written by <strong>{{ site.author }}</strong><date>{{ page.date | date: "%B %-d, %Y" }}</date>.</small> {{ content }} </article> 

Если вы знакомы с Rails, {{ content }} похож на с точки зрения макетов. В этом случае он уступает контенту, переданному в каждом посте. Обратите внимание, что мы также использовали page.title и page.date а не post.title и т. Д., Потому что мы вызываем переменную, которая передается только на страницу (макет), а не через итерацию.

Теперь, если вы переходите по ссылке на сообщение, отображается хороший заголовок и некоторая мета-информация о сообщении на этой странице.

Вывод

Вот оно! Полностью функциональный блог Jekyll. Немного больше стиля, и у вас есть что написать, чтобы использовать желание вашего сердца. Если вы хотите узнать больше о том, что может сделать Джекилл, ознакомьтесь с документами. Удачного блога!