如何在Hakyll html中为帖子的第二个目录提供第二个列表?

问题描述

我在索引页面上有一个部分,列出了posts / *目录中的帖子。我想再有一个部分列出一个来自bibs / *目录的帖子。

所以,它看起来像:

                    <section id="one" class="wrapper style2 spotlights">
                        <section>
                            <div class="content">
                                <div class="inner">
                                    <h2>Blog posts</h2>
                                    $body$
                                    <p><a href="./posts.html">See all.</a></p>
                                </div>
                            </div>
                        </section>
                    </section>
                    <!-- Two -->
                    <section id="two" class="wrapper style1 fade-up">
                        <div class="inner">
                            <h2>Bibliographies</h2>
                            $body2$
                            <p><a href="./bibs.html">See all bibs.</a></p>
                        </div>
                    </section>

当前,我收到错误消息

[ERROR] Hakyll.Web.Template.applyTemplate: Failed to apply template templates/index.html to item index.html:
    In expr '$body2$',Tried field title,Tried field date,Tried field body,No 'body2' field in Metadata of item index.html,Tried field url,Tried field path,Missing field 'body2' in context

下面是我用于常规帖子的代码-如何复制相同列表,但复制其他目录? (为了节省长度,我剪切了不相关的代码,如果您想查看项目源,可以here,相关文件分别为site.hstemplates/index.html。)谢谢您的支持时间,请让我知道是否可以澄清任何事情或提供其他信息。

defaultCtx :: Context String
defaultCtx = dateField "date" "%B %e,%Y" <> defaultContext

basicCtx :: String -> Context String
basicCtx title = constField "title" title <> defaultCtx

homeCtx :: Context String
homeCtx = basicCtx "Home"

allPostsCtx :: Context String
allPostsCtx = basicCtx "All posts"

FeedCtx :: Context String
FeedCtx = bodyField "description" <> defaultCtx

tagsCtx :: Tags -> Context String
tagsCtx tags = tagsField "prettytags" tags <> defaultCtx

postsCtx :: String -> String -> Context String
postsCtx title list = constField "body" list <> basicCtx title

externalizeUrls :: String -> Item String -> Compiler (Item String)
externalizeUrls root item = return $ withUrls ext <$> item
  where
    ext x = if isExternal x then x else root ++ x

unExternalizeUrls :: String -> Item String -> Compiler (Item String)
unExternalizeUrls root item = return $ withUrls unExt <$> item
  where
    unExt x = fromMaybe x $ stripPrefix root x

postList :: Tags -> Pattern -> ([Item String] -> Compiler [Item String]) -> Compiler String
postList tags pattern preprocess' = do
    postItemTpl <- loadBody "templates/postitem.html"
    posts <- preprocess' =<< loadAll pattern
    applyTemplateList postItemTpl (tagsCtx tags) posts

main :: IO ()
main = hakyllWith configuration $ do
    -- Build tags
    tags <- buildTags "posts/*" $ fromCapture "tags/*.html"
    let tagsCtx' = tagsCtx tags

    match "posts/*" $ do
        route   $ setExtension ".html"
        compile $ pandocCompiler
            >>= loadAndApplyTemplate "templates/post.html"     tagsCtx'
            >>= (externalizeUrls     $ FeedRoot FeedConfiguration)
            >>= saveSnapshot         "content"
            >>= (unExternalizeUrls   $ FeedRoot FeedConfiguration)
            >>= loadAndApplyTemplate "templates/default.html"  tagsCtx'
            >>= relativizeUrls

    create ["posts.html"] $ do
        route idRoute
        compile $ do
            list <- postList tags "posts/*" recentFirst
            makeItem list
                >>= loadAndApplyTemplate "templates/posts.html"   allPostsCtx
                >>= loadAndApplyTemplate "templates/default.html" allPostsCtx
                >>= relativizeUrls

    create ["index.html"] $ do
        route idRoute
        compile $ do
            list <- postList tags "posts/*" (fmap (take 10) . recentFirst)
            makeItem list
                >>= loadAndApplyTemplate "templates/index.html"   homeCtx
                >>= loadAndApplyTemplate "templates/default.html" homeCtx
                >>= relativizeUrls

    tagsRules tags $ \tag pattern -> do
        route idRoute
        compile $ do
            list <- postList tags pattern recentFirst

            let title       = "Posts tagged '" ++ tag ++ "'"
            let defaultCtx' = basicCtx title
            let postsCtx'   = postsCtx title list

            makeItem ""
                >>= loadAndApplyTemplate "templates/posts.html"   postsCtx'
                >>= loadAndApplyTemplate "templates/default.html" defaultCtx'
                >>= relativizeUrls

解决方法

您可以使用field<>组合器来扩展Context(在这种情况下为homeCtx),并在某些标签下添加列表的内容。在这里,我将标签bodybody2重命名为postsbibs,因为body是在Hakyll中具有特殊含义的标签。 记住还要重命名templates/index.html中的标签。

    -- Index
    create ["index.html"] $ do
        route idRoute
        compile $ do
            let mkposts = postList tags "posts/*" (fmap (take 10) . recentFirst)
                mkbibs = bibList tags "bibs/*" (fmap (take 10) . recentFirst)
                homeCtx' = field "posts" (const mkposts)  -- Populate the context with those fields
                        <> field "bibs" (const mkbibs)    --
                        <> homeCtx
            makeItem ""  -- This doesn't matter since the next template does not contain "body" (after renaming it to "posts")
                >>= loadAndApplyTemplate "templates/index.html"   homeCtx'  -- This template mentions "posts" and "bibs",which will be looked up in homeCtx'
                >>= loadAndApplyTemplate "templates/default.html" homeCtx'
                >>= relativizeUrls