我正在尝试做类似 what's described in this tutorial 的事情,即,向我的 Hakyll 博客添加标签,但不是为每个标签生成一个页面,只需一个页面列出所有标签及其帖子。所以给出了 Post1
已标记 Tag1
, 和 Post2
已标记 Tag1, Tag2
, 和 Post3
已标记 Tag2
, 我的 tags.html
看起来像这样:
Tag1:
- Post1
- Post2
Tag2:
- Post2
- Post3
但我是一个 Haskell 初学者,我并不完全理解 Hakyll 的所有 monadic 上下文。这是我到目前为止所拥有的:
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
,但它不起作用。)所以我很难考虑如何继续。The complete file is here on 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
The full code, as it currently stands, is up here.
对此的任何帮助将不胜感激。我知道所有文档,但我似乎无法将其转换为工作代码。
最佳答案
我已经修改了你的 site.hs
创建一个基本的标签列表页面,我认为它具有所需的结构:标签列表,每个标签都包含带有该标签的帖子列表。
以下是我为使其正常工作而必须做的每件事的摘要:
{-# LANGUAGE ViewPatterns #-}
不是绝对必要的,但是我曾经使用过的一个很好的语言扩展。我想我会使用/提及它,因为你提到你是 Haskell 的初学者,很高兴知道。
tags <- buildTags "posts/*" (fromCapture "tags/*.html")
与
buildTags
相比,此行需要进行两项更改在您的初始 site.hs
.一是它可能应该移出个人match
条款进入顶级Rules
monad,以便我们可以根据需要创建单独的标签页面。另一个是捕获类似地从 "tags.html#"
更改。至 "tags/*.html"
.这很重要,因为 Hakyll 想要每个 Item
拥有独一无二的Identifier
,并不是每个标签页都是一样的。具有唯一标识符的单个标记页面可能不是绝对必要的,但简化了其余的设置,因为许多 Hakyll 机器假设它们存在。特别是
Tags:
单个帖子描述中的行以前也没有正确呈现。出于同样的原因,实际上使这些单独的标记页面可路由是一个好主意:在顶级
Rules
中没有此节monad,每个帖子上的标签在默认情况下不会正确呈现 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
field 。对于 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
开头,就像你的例子一样。但是 Hakyll 希望结果是 Item
,所以我们必须使用 mkItem
把它包起来. Item
里面有什么|除了 body ?只是一个 Identifier
,以及 Tags
object 恰好包含一个字段,告诉我们如何获取它!所以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$"
这只是一个呈现嵌套列表的非常简单的模板;你当然可以做各种事情来使它更漂亮/更好看。
我已经对你的 repo 做了 PR,以便你可以在上下文中看到这些变化 here .
关于haskell - 在 Hakyll 中,如何生成标签页面?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52805193/