我正在尝试做类似本教程中描述的内容,即向我的Hakyll博客添加标签,但不是为每个标签生成一个页面,只需要一个页面列出所有标签及其帖子.所以给定一个Post1
标记Tag1
,Post2
标记Tag1, Tag2
和Post3
标记Tag2
,我tags.html
会看起来像这样:
Tag1:
- Post1
- Post2
Tag2:
- Post2
- Post3
Run Code Online (Sandbox Code Playgroud)
但我是哈斯克尔的初学者,我并不完全理解哈基尔的所有monadic环境.这是我到目前为止所拥有的:
create ["tags.html"] $ do
route idRoute
tags <- buildTags "posts/*" (fromCapture "tags.html")
compile $
makeItem ""
>>= applyTemplate tagListTemplate defaultContext
>>= applyTemplate defaultTemplate defaultContext
>>= relativizeUrls
>>= cleanIndexUrls
Run Code Online (Sandbox Code Playgroud)
问题是,Tags
在我的博客中,我真的不知道是什么.我似乎无法将它们打印出来进行调试.(我尝试添加print tags
,但它不起作用.)所以我很难想到如何继续这个.
任何帮助深表感谢.
更新:我仍然没有更接近解决这个问题.这是我现在正在尝试的内容:
create ["tags.html"] $ do
route idRoute
tags <- buildTags "posts/*" (fromCapture "tags.html#")
let tagList = tagsMap tags
compile $ do
makeItem ""
>>= applyTemplate tagListTemplate (defaultCtxWithTags tags)
Run Code Online (Sandbox Code Playgroud)
随着:
-- Add tags to default context, for tag listing
defaultCtxWithTags :: Tags -> Context String
defaultCtxWithTags tags = listField "tags" defaultContext (return (tagsMap tags)) `mappend` defaultContext
Run Code Online (Sandbox Code Playgroud)
任何有关这方面的帮助将非常感激.我知道所有文档,但我似乎无法将其转换为工作代码.
我已经修改了您的site.hs
代码,以创建一个基本的标签列表页面,该页面相信具有所需的结构:一个标签列表,每个标签列表都包含带有该标签的帖子列表。
这是我要使其正常工作必须做的每件事的摘要:
{-# LANGUAGE ViewPatterns #-}
Run Code Online (Sandbox Code Playgroud)
并非绝对必要,但我曾经使用过一种不错的语言扩展。我以为我会使用/提及它,因为您提到您是Haskell的初学者,并且很高兴知道。
tags <- buildTags "posts/*" (fromCapture "tags/*.html")
Run Code Online (Sandbox Code Playgroud)
与buildTags
您的initial 相比,此行需要进行两项更改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
Run Code Online (Sandbox Code Playgroud)
好吧,这是预备赛。现在到主要景点:
defaultCtxWithTags tags = listField "tags" tagsCtx getAllTags `mappend`
defaultContext
Run Code Online (Sandbox Code Playgroud)
好吧,这里添加的重要内容是某个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
Run Code Online (Sandbox Code Playgroud)
什么是getAllTags
做什么?嗯,tagsMap tags
就像您的示例一样,它以开头。但是Hakyll希望结果为an 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
Run Code Online (Sandbox Code Playgroud)
一切都是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
Run Code Online (Sandbox Code Playgroud)
getPosts
给定它的每个帖子,大多数情况下只是使用该load
函数来获取Item
它们的Identifier
---就像loadAll
您在索引页面上获取所有帖子一样,但是它只给您一个帖子。左侧的模式匹配看起来很奇怪ViewPatterns
:实际上是在说要使该模式匹配,->
((_, is)
)右侧的模式应与将左侧(即itemBody
)函数应用于该模式的结果相匹配。论点。
postsCtx :: Context String
postsCtx = postCtxWithTags tags
Run Code Online (Sandbox Code Playgroud)
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$"
Run Code Online (Sandbox Code Playgroud)
这只是一个非常简单的模板,用于呈现嵌套列表。当然,您可以做各种事情使它看起来更漂亮/更黑。
我已经对您的仓库进行了公关,以便您可以在此处查看这些更改。