В Hakyll, как я могу создать страницу тегов? - PullRequest
0 голосов
/ 14 октября 2018

Я пытаюсь сделать что-то вроде , что описано в этом уроке , то есть добавить теги в мой блог Hakyll, но вместо создания страницы для каждого тега, просто одна страница, которая перечисляет все тегии их посты.Таким образом, учитывая Post1 с тегом Tag1 и Post2 с тегом Tag1, Tag2 и Post3 с тегом Tag2, мой tags.html будет выглядеть так:

 Tag1: 
  - Post1
  - Post2
 Tag2: 
  - Post2
  - Post3

НоЯ новичок в Haskell, и я не до конца понимаю все монадические контексты Hakyll.Вот что у меня есть:

create ["tags.html"] $ do
    route idRoute
    tags <- buildTags "posts/*" (fromCapture "tags.html")
    compile $
        makeItem ""
            >>= applyTemplate tagListTemplate defaultContext
            >>= applyTemplate defaultTemplate defaultContext
            >>= relativizeUrls
            >>= cleanIndexUrls

Проблема в том, что я действительно не знаю, что такое Tags в контексте моего блога.Я не могу распечатать их для отладки.(Я попытался добавить print tags, но это не сработало.) Так что мне очень трудно думать о том, что делать дальше.

Полный файл находится здесь, на GitHub.

Любая помощь очень ценится.

Обновление : Я все еще не слишком близок к тому, чтобы выяснить это.Вот что я сейчас пытаюсь:

create ["tags.html"] $ do
        route idRoute
        tags <- buildTags "posts/*" (fromCapture "tags.html#")
        let tagList = tagsMap tags
        compile $ do
            makeItem ""
              >>= applyTemplate tagListTemplate (defaultCtxWithTags tags)

вместе с:

-- Add tags to default context, for tag listing
defaultCtxWithTags :: Tags -> Context String
defaultCtxWithTags tags = listField "tags" defaultContext (return (tagsMap tags)) `mappend` defaultContext

Полный код в том виде, в котором он есть в данный момент, находится здесь.

Любая помощь с этим будет высоко ценится.Мне известна вся документация, но я не могу перевести это в рабочий код.

Ответы [ 2 ]

0 голосов
/ 22 ноября 2018

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

Воткраткое описание каждой из вещей, которые мне пришлось сделать, чтобы заставить его работать:

{-# LANGUAGE ViewPatterns #-}

Не обязательно, но хорошее расширение языка, которое я использую один раз.Я думал, что буду использовать / упомянуть об этом, так как вы упомянули, что вы новичок в Haskell, и о нем приятно знать.

tags <- buildTags "posts/*" (fromCapture "tags/*.html")

В этой строке необходимо внести два изменения по сравнению с buildTags в вашем начальном site.hs.Один из них заключается в том, что он, вероятно, должен быть перемещен из отдельных предложений match в монаду верхнего уровня Rules, чтобы при необходимости мы могли создавать отдельные страницы тегов.Другое заключается в том, что захват был аналогичным образом изменен с "tags.html#" на "tags/*.html".Это важно, потому что Hakyll хочет, чтобы у каждого Item был уникальный Identifier, и не все страницы тегов одинаковы.

Наличие отдельных страниц тегов с уникальными идентификаторами может не быть строго необходимым, но упрощаетостальная часть установки, так как большая часть машин Hakyll предполагает, что они существуют.В частности, строка Tags: в отдельных описаниях постов ранее также не отображалась корректно.

По той же причине неплохо было бы на самом деле сделать эти отдельные страницы тегов маршрутизируемыми: без этого раздела вНа верхнем уровне Rules монада, теги на каждом сообщении не будут правильно отображаться с используемым по умолчанию tagsField, так как они не могут понять, как сделать ссылку на отдельную страницу тега:

tagsRules tags $ \tag pat -> do
    route idRoute
    compile $ do
        posts <- recentFirst =<< loadAll pat
        let postCtx = postCtxWithTags tags
            postsField = listField "posts" postCtx (pure posts)
            titleField = constField "title" ("Posts tagged \""++tag++"\"")
            indexCtx = postsField <> titleField <> defaultContext
        makeItem "" >>= applyTemplate postListTemplate indexCtx
                    >>= applyTemplate defaultTemplate defaultContext
                    >>= relativizeUrls
                    >>= cleanIndexUrls

Хорошо, это предварительные экзамены.Теперь перейдем к главной достопримечательности:

defaultCtxWithTags tags = listField "tags" tagsCtx getAllTags         `mappend`
                          defaultContext

Хорошо, здесь добавлено важное поле tags.Он будет содержать один элемент для каждой вещи, возвращаемой getAllTags, а поля для каждого элемента будут заданы tagsCtx.

  where getAllTags :: Compiler [Item (String, [Identifier])]
        getAllTags = pure . map mkItem $ tagsMap tags
          where mkItem :: (String, [Identifier]) -> Item (String, [Identifier])
                mkItem x@(t, _) = Item (tagsMakeId tags t) x

Что делает getAllTags?Ну, это начинается с tagsMap tags, как и ваш пример.Но Хэкилл хочет, чтобы результат был Item, поэтому мы должны обернуть его, используя mkItem.Что в Item кроме тела?Просто Identifier, и объект Tags содержит поле, которое говорит нам, как это получить!Так что mkItem просто использует tagsMakeId для получения идентификатора и оборачивает данное тело этим идентификатором.

Как насчет tagsCtx?

        tagsCtx :: Context (String, [Identifier])
        tagsCtx = listFieldWith "posts" postsCtx getPosts             `mappend`
                  metadataField                                       `mappend`
                  urlField "url"                                      `mappend`
                  pathField "path"                                    `mappend`
                  titleField "title"                                  `mappend`
                  missingField

Все, что начинается с metadataField, этопросто обычные вещи, которые мы ожидаем получить от defaultContext;мы не можем использовать defaultContext здесь, так как он хочет добавить bodyField, но тело этого Item не является строкой (но вместо этого гораздо более полезная для нас структура Haskell, представляющая тег).Интересным моментом является строка, которая добавляет поле posts, которое должно выглядеть немного знакомым.Большая разница в том, что он использует listFieldWith вместо listField, что в основном означает, что getPosts получает дополнительный аргумент, который является телом Item, в котором находится это поле.В данном случае это запись тега из tagsMap.

          where getPosts :: Item (String, [Identifier])
                         -> Compiler [Item String]
                getPosts (itemBody -> (_, is)) = mapM load is

getPosts, в основном просто использует функцию load, чтобы получить Item для каждого поста с учетом Identifier -- это очень похоже на loadAll, который вы делаете, чтобы получить все сообщения на странице индекса, но он просто дает вам одно сообщение.Странное на первый взгляд совпадение с шаблоном в действии ViewPatterns в действии: в основном это говорит о том, что для соответствия этому шаблону шаблон справа от -> (то есть (_, is)) должен соответствовать результату примененияФункция слева (т.е. itemBody) для аргумента.

                postsCtx :: Context String
                postsCtx = postCtxWithTags tags

postsCtx очень проста: точно так же postCtxWithTags используется везде, где мы визуализируем сообщение.

Это все, что нужно, чтобы получить Context со всем, что вы хотите;осталось только создать шаблон для его визуализации!

tagListTemplateRaw :: Html
tagListTemplateRaw =
  ul $ do
    "$for(tags)$"
    li ! A.class_ "" $ do
      a ! href "$url$" $ "$title$"
      ul $ do
        "$for(posts)$"
        li ! A.class_ "" $ do
          a ! href "$url$" $ "$title$"
        "$endfor$"
    "$endfor$"

Это просто очень простой шаблон, который отображает вложенные списки;Вы, конечно, могли бы делать разные вещи, чтобы сделать его более привлекательным / привлекательным.

Я сделал пиар в вашем репо, чтобы вы могли увидеть эти изменения в контексте здесь .

0 голосов
/ 01 ноября 2018

Вот что мы сделали, чтобы добиться такого поведения на нашей веб-странице:

Создание тегов веб-страницы Kowainik

И пример страницы тегов:

https://kowainik.github.io/tags/haskell

Вы можете задать любые вопросы по коду:)

...