{-|
Module: IHP.PageHead.ViewFunctions
Description: Manage the @<title>@ and @<meta>@ tags of your HTML pages
Copyright: (c) digitally induced GmbH, 2021
-}
module IHP.PageHead.ViewFunctions
( pageTitle
, pageTitleOrDefault
, pageTitleOrNothing
, descriptionOrDefault
, ogTitleOrDefault
, ogTypeOrDefault
, ogDescriptionOrDefault
, ogUrl
, ogImage
, module IHP.PageHead.ControllerFunctions -- | Re-export as we want to call setTitle from the beforeRender hook
) where

import IHP.Prelude
import IHP.PageHead.Types
import IHP.Controller.Context
import IHP.PageHead.ControllerFunctions
import IHP.HSX.QQ (hsx)
import Text.Blaze.Html5 (Html)

-- | Returns the current page title. The title can be set using @setTitle "my title"@ from the action.
--
-- If the title hasn't been set yet, this will return an empty string. You can also use 'pageTitleOrDefault' to pass a custom default title.
--
-- You can use this inside your @<title>@ tag like this:
--
-- > [hsx|
-- >     <head>
-- >         <title>{pageTitle}</title>
-- >     </head>
-- > |]
--
--
-- *App-wide default title:*
--
-- You can set a app-wide default title by calling 'setTitle' from the @FrontController.hs@:
--
-- > instance InitControllerContext Web where
-- >     initContext = do
-- >         setLayout defaultLayout
-- >         initAutoRefresh
-- >         setTitle "Jobs"
--
--
-- *View-specific title:*
-- 
-- You can set a custom title inside the view by calling 'setTitle' inside the 'beforeRender' hook.
--
-- > module JobSite.View.JobPositions.Show where
-- > 
-- > instance View ShowView where
-- >     beforeRender ShowView { .. } = do
-- >         setTitle "Custom title"
-- > 
-- >     html ShowView { .. } = [hsx|..|]
pageTitle :: (?context :: ControllerContext) => Text
pageTitle :: Text
pageTitle = (?context::ControllerContext) => Text -> Text
Text -> Text
pageTitleOrDefault Text
""

-- | Returns the current page title, like 'pageTitle' but returns a provided default value instead of an empty string if no title is set.
--
-- You can use this inside your @<title>@ tag like this:
--
-- > [hsx|
-- >     <head>
-- >         <title>{pageTitleOrDefault "My Application"}</title>
-- >     </head>
-- > |]
pageTitleOrDefault :: (?context :: ControllerContext) => Text -> Text
pageTitleOrDefault :: Text -> Text
pageTitleOrDefault Text
defaultValue = Maybe Text
(?context::ControllerContext) => Maybe Text
pageTitleOrNothing Maybe Text -> (Maybe Text -> Text) -> Text
forall t1 t2. t1 -> (t1 -> t2) -> t2
|> Text -> Maybe Text -> Text
forall a. a -> Maybe a -> a
fromMaybe Text
defaultValue

-- | Returns the current page title or Nothing if not set yet
pageTitleOrNothing :: (?context :: ControllerContext) => Maybe Text
pageTitleOrNothing :: Maybe Text
pageTitleOrNothing = case (?context::ControllerContext, Typeable PageTitle) =>
Maybe PageTitle
forall value.
(?context::ControllerContext, Typeable value) =>
Maybe value
maybeFromFrozenContext @PageTitle of
        Just (PageTitle Text
title) -> Text -> Maybe Text
forall a. a -> Maybe a
Just Text
title
        Maybe PageTitle
Nothing -> Maybe Text
forall a. Maybe a
Nothing


-- | Returns the meta og:title element. The og:title can be set using @setOGTitle "my title"@ from the view.
--
-- You can use this inside your Layout like this:
--
-- > [hsx|
-- >     <head>
-- >         <title>{pageTitle}</title>
-- >         {ogTitleOrDefault "default title"}
-- >     </head>
-- > |]
--
--
-- *View-specific og:title:*
-- 
-- You can override the default og:title inside the view by calling 'setOGTitle' inside the 'beforeRender' hook:
--
-- > module JobSite.View.JobPositions.Show where
-- > 
-- > instance View ShowView where
-- >     beforeRender ShowView { .. } = do
-- >         setOGTitle "Custom title"
-- > 
-- >     html ShowView { .. } = [hsx|..|]
ogTitleOrDefault :: (?context :: ControllerContext) => Text -> Html
ogTitleOrDefault :: Text -> Html
ogTitleOrDefault Text
defaultValue = [hsx|<meta property="og:title" content={content}/>|]
    where
        content :: Text
content = case (?context::ControllerContext, Typeable OGTitle) => Maybe OGTitle
forall value.
(?context::ControllerContext, Typeable value) =>
Maybe value
maybeFromFrozenContext @OGTitle of
            Just (OGTitle Text
title) -> Text
title
            Maybe OGTitle
Nothing -> Text
defaultValue

-- | Returns @<meta name="description" content="Lorem Ipsum">@ element. The description can be set using @setDescription "my description"@ from the view.
--
-- You can use this inside your Layout like this:
--
-- > [hsx|
-- >     <head>
-- >         <title>{pageTitle}</title>
-- >         {descriptionOrDefault "CO2 Database"}
-- >     </head>
-- > |]
--
--
-- *View-specific description:*
-- 
-- You can override the default description inside the view by calling 'setDescription' inside the 'beforeRender' hook:
--
-- > module JobSite.View.JobPositions.Show where
-- > 
-- > instance View ShowView where
-- >     beforeRender ShowView { .. } = do
-- >         setDescription "The CO2 Footprint of beef is about 67kg CO2 per 1kg of beef."
-- > 
-- >     html ShowView { .. } = [hsx|..|]
descriptionOrDefault :: (?context :: ControllerContext) => Text -> Html
descriptionOrDefault :: Text -> Html
descriptionOrDefault Text
defaultValue = [hsx|<meta name="description" content={content}/>|]
    where
        content :: Text
content = case (?context::ControllerContext, Typeable PageDescription) =>
Maybe PageDescription
forall value.
(?context::ControllerContext, Typeable value) =>
Maybe value
maybeFromFrozenContext @PageDescription of
            Just (PageDescription Text
description) -> Text
description
            Maybe PageDescription
Nothing -> Text
defaultValue

-- | Returns the meta og:type element. The og:type can be set using @setOGType "data"@ from the view.
--
-- You can use this inside your Layout like this:
--
-- > [hsx|
-- >     <head>
-- >         <title>{pageTitle}</title>
-- >         {ogTypeOrDefault "data"}
-- >     </head>
-- > |]
--
--
-- *View-specific og:type:*
-- 
-- You can override the default og:type inside the view by calling 'setOGType' inside the 'beforeRender' hook:
--
-- > module JobSite.View.JobPositions.Show where
-- > 
-- > instance View ShowView where
-- >     beforeRender ShowView { .. } = do
-- >         setOGType "mytype"
-- > 
-- >     html ShowView { .. } = [hsx|..|]
ogTypeOrDefault :: (?context :: ControllerContext) => Text -> Html
ogTypeOrDefault :: Text -> Html
ogTypeOrDefault Text
defaultValue = [hsx|<meta property="og:type" content={content}/>|]
    where
        content :: Text
content = case (?context::ControllerContext, Typeable OGType) => Maybe OGType
forall value.
(?context::ControllerContext, Typeable value) =>
Maybe value
maybeFromFrozenContext @OGType of
            Just (OGType Text
type_) -> Text
type_
            Maybe OGType
Nothing -> Text
defaultValue

-- | Returns the meta og:description element. The og:description can be set using @setOGDescription "my description"@ from the view.
--
-- You can use this inside your Layout like this:
--
-- > [hsx|
-- >     <head>
-- >         <title>{pageTitle}</title>
-- >         {ogDescriptionOrDefault "CO2 Database"}
-- >     </head>
-- > |]
--
--
-- *View-specific og:description:*
-- 
-- You can override the default og:description inside the view by calling 'setOGDescription' inside the 'beforeRender' hook:
--
-- > module JobSite.View.JobPositions.Show where
-- > 
-- > instance View ShowView where
-- >     beforeRender ShowView { .. } = do
-- >         setOGDescription "The CO2 Footprint of beef is about 67kg CO2 per 1kg of beef."
-- > 
-- >     html ShowView { .. } = [hsx|..|]
ogDescriptionOrDefault :: (?context :: ControllerContext) => Text -> Html
ogDescriptionOrDefault :: Text -> Html
ogDescriptionOrDefault Text
defaultValue = [hsx|<meta property="og:description" content={content}/>|]
    where
        content :: Text
content = case (?context::ControllerContext, Typeable OGDescription) =>
Maybe OGDescription
forall value.
(?context::ControllerContext, Typeable value) =>
Maybe value
maybeFromFrozenContext @OGDescription of
            Just (OGDescription Text
description) -> Text
description
            Maybe OGDescription
Nothing -> Text
defaultValue


-- | Returns the meta og:url element if @setOGUrl "https://example.com/"@ was called before.
--
-- You can use this inside your Layout like this:
--
-- > [hsx|
-- >     <head>
-- >         <title>{pageTitle}</title>
-- >         {ogUrl}
-- >     </head>
-- > |]
--
-- When 'setOGUrl' is not called, no meta tag will be rendered.
--
-- *Setting og:url:*
-- 
-- You can set the og:url inside the view by calling 'setOGUrl' inside the 'beforeRender' hook:
--
-- > module JobSite.View.JobPositions.Show where
-- > 
-- > instance View ShowView where
-- >     beforeRender ShowView { .. } = do
-- >         setOGUrl (urlTo ShowAction { .. })
-- > 
-- >     html ShowView { .. } = [hsx|..|]
ogUrl :: (?context :: ControllerContext) => Html
ogUrl :: Html
ogUrl = case (?context::ControllerContext, Typeable OGUrl) => Maybe OGUrl
forall value.
(?context::ControllerContext, Typeable value) =>
Maybe value
maybeFromFrozenContext @OGUrl of
    Just (OGUrl Text
url) -> [hsx|<meta property="og:url" content={url}/>|]
    Maybe OGUrl
Nothing -> Html
forall a. Monoid a => a
mempty


-- | Returns the meta og:image element if @setOGImage "https://example.com/image.png"@ was called before.
--
-- You can use this inside your Layout like this:
--
-- > [hsx|
-- >     <head>
-- >         <title>{pageTitle}</title>
-- >         {ogImage}
-- >     </head>
-- > |]
--
-- When 'setOGImage' is not called, no meta tag will be rendered.
--
-- *Setting og:image:*
-- 
-- You can set the og:image inside the view by calling 'setOGImage' inside the 'beforeRender' hook:
--
-- > module JobSite.View.JobPositions.Show where
-- > 
-- > instance View ShowView where
-- >     beforeRender ShowView { .. } = do
-- >         setOGImage "https://example.com/image.png"
-- > 
-- >     html ShowView { .. } = [hsx|..|]
ogImage :: (?context :: ControllerContext) => Html
ogImage :: Html
ogImage = case (?context::ControllerContext, Typeable OGImage) => Maybe OGImage
forall value.
(?context::ControllerContext, Typeable value) =>
Maybe value
maybeFromFrozenContext @OGImage of
    Just (OGImage Text
url) -> [hsx|<meta property="og:image" content={url}/>|]
    Maybe OGImage
Nothing -> Html
forall a. Monoid a => a
mempty