如何更改 IHP 应用程序中的 <title>?

How do I change the <title> in an IHP app?

我看到 <title>App</title> 在 Web/View/Layout.hs 中硬编码在 defaultLayout 中,并且 Web/View/Context.hs 有

    let viewContext = ViewContext {
            requestContext = ?requestContext,
            user = currentUserOrNothing,
            flashMessages,
            controllerContext = ?controllerContext,
            layout = let ?viewContext = viewContext in defaultLayout
        }

但是如何为特定视图使用不同的函数?视图 class 的 html 功能似乎没有 return 新的上下文,只是页面的一部分的新 html。

明白了:有一个 beforeRender 函数可以在 View class 中覆盖,您可以在其中设置它,例如

data ShowView = ShowView { targets :: [Include "comments" Post], postTitle :: Text }

instance View ShowView ViewContext where
    beforeRender (context, view) = (context { layout = myLayout (postTitle view) }, view)
    html ShowView { .. } = [hsx| … |]

(并在Web/Controller/Posts.hs中设置postTitle),然后将Web/View/Layout.hs改为do

defaultLayout :: Html -> Html
defaultLayout = myLayout "App"

myLayout :: Text -> Html -> Html
myLayout title inner = H.docTypeHtml ! A.lang "en" $ [hsx|
<head>
    {metaTags}

    {stylesheets}
    {scripts}

    <title>{title}</title>
</head>
<body>
    <div class="container mt-4">
        {renderFlashMessages}
        {inner}
    </div>
</body>
|]

现在有一个 pageTitle 您可以在视图(例如您的布局)中使用的功能,如下所示:

[hsx|
    <head>
        <title>{pageTitle}</title>
    </head>
|]

https://github.com/digitallyinduced/ihp/blob/18f104da69c526ff9e8ad3a6cdaedc6d39afb38c/IHP/PageTitle/ViewFunctions.hs#L54

这又可以使用 setTitle

进行设置
action ShowProjectAction { projectId } = do
    project <- fetch projectId
    setTitle (get #title project)

https://github.com/digitallyinduced/ihp/blob/d98c3d6eb8145d859c9ce461e7d1367be5be7337/IHP/PageTitle/ControllerFunctions.hs#L32

最新的 IHP 还生成了以下布局 s.t。您可以通过后备自动获得它:

defaultLayout :: Html -> Html
defaultLayout inner = H.docTypeHtml ! A.lang "en" $ [hsx|
<head>
    {metaTags}

    {stylesheets}
    {scripts}

    <title>{pageTitleOrDefault "App"}</title>
</head>
<body>
    <div class="container mt-4">
        {renderFlashMessages}
        {inner}
    </div>
</body>
|]