-- | Rules for standalone pages
module MathiasSM.Rules.SinglePages (Page (..), page, processPage, pageCompiler) where

import Hakyll (
    Compiler,
    Context,
    Identifier,
    Item,
    Rules,
    compile,
    getResourceString,
    matchMetadata,
    metadataRoute,
    route,
 )
import MathiasSM.CleanURL (pathRoute)
import MathiasSM.Compile (applyTemplates, finish, runPandoc)
import MathiasSM.Config (SiteConfig, minimalTemplate, pageTemplate, pagesPattern, siteEnv)
import MathiasSM.Content (isHidden, isTemplated)
import MathiasSM.Context (globalContext)
import MathiasSM.Context.Nav (navContext)
import MathiasSM.Theme (applyContentAsTemplate)

-- | A standalone page, backed by content/writings/<pageName>.* and routed by its `path:`
data Page = Page
    { Page -> String
pageName :: String
    , Page -> Compiler (Context String)
pageContext :: Compiler (Context String)
    -- ^ Context for the page body and its templates
    , Page -> [Identifier]
pageTemplates :: [Identifier]
    -- ^ Extra templates, applied between the minimal and page templates
    }

-- | A page with the minimal context and no extra templates
page :: SiteConfig -> String -> Page
page :: SiteConfig -> String -> Page
page SiteConfig
cfg String
name = Page{pageName :: String
pageName = String
name, pageContext :: Compiler (Context String)
pageContext = Context String -> Compiler (Context String)
forall a. a -> Compiler a
forall (m :: * -> *) a. Monad m => a -> m a
return (SiteConfig -> Context String
globalContext SiteConfig
cfg), pageTemplates :: [Identifier]
pageTemplates = []}

-- | Compiles a standalone page's body (shared by 'processPage' and the dev example pages)
pageCompiler :: SiteConfig -> Page -> Compiler (Item String)
pageCompiler :: SiteConfig -> Page -> Compiler (Item String)
pageCompiler SiteConfig
cfg Page{String
pageName :: Page -> String
pageName :: String
pageName, Compiler (Context String)
pageContext :: Page -> Compiler (Context String)
pageContext :: Compiler (Context String)
pageContext, [Identifier]
pageTemplates :: Page -> [Identifier]
pageTemplates :: [Identifier]
pageTemplates} = do
    ctx <- Compiler (Context String)
pageContext
    templated <- isTemplated
    getResourceString
        >>= (if templated then applyContentAsTemplate cfg ctx else return)
        >>= runPandoc
        >>= applyTemplates ctx ([minimalTemplate cfg] <> pageTemplates <> [pageTemplate cfg])
        >>= finish cfg (navContext cfg pageName <> ctx)

-- | Processes a standalone page, routed by its `path:` front matter
processPage :: SiteConfig -> Page -> Rules ()
processPage :: SiteConfig -> Page -> Rules ()
processPage SiteConfig
cfg page' :: Page
page'@Page{String
pageName :: Page -> String
pageName :: String
pageName} = Pattern -> (Metadata -> Bool) -> Rules () -> Rules ()
matchMetadata (SiteConfig -> String -> Pattern
pagesPattern SiteConfig
cfg String
pageName) (Bool -> Bool
not (Bool -> Bool) -> (Metadata -> Bool) -> Metadata -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Env -> Metadata -> Bool
isHidden (SiteConfig -> Env
siteEnv SiteConfig
cfg)) (Rules () -> Rules ()) -> Rules () -> Rules ()
forall a b. (a -> b) -> a -> b
$ do
    Routes -> Rules ()
route (Routes -> Rules ()) -> Routes -> Rules ()
forall a b. (a -> b) -> a -> b
$ (Metadata -> Routes) -> Routes
metadataRoute Metadata -> Routes
pathRoute
    Compiler (Item String) -> Rules ()
forall a.
(Binary a, Typeable a, Writable a) =>
Compiler (Item a) -> Rules ()
compile (Compiler (Item String) -> Rules ())
-> Compiler (Item String) -> Rules ()
forall a b. (a -> b) -> a -> b
$ SiteConfig -> Page -> Compiler (Item String)
pageCompiler SiteConfig
cfg Page
page'