-- | Rules for the projects group: its index page and the projects
module MathiasSM.Rules.Showcase (processShowcaseGroup) where

import Data.List (sortOn)
import Hakyll (
    Compiler,
    Context,
    Item (Item, itemBody, itemIdentifier),
    Rules,
    compile,
    getResourceString,
    listField,
    loadAll,
    match,
 )
import MathiasSM.Config (SiteConfig, projectsGroup, projectsPattern, resolveTemplate)
import MathiasSM.Content (requireProject, showcaseKey)
import MathiasSM.Context (globalContext)
import MathiasSM.Context.Project (projectContext)
import MathiasSM.Rules.SinglePages (Page (..), page, processPage)

-- | Processes the projects group: its index page and the projects it lists
processShowcaseGroup :: SiteConfig -> Rules ()
processShowcaseGroup :: SiteConfig -> Rules ()
processShowcaseGroup SiteConfig
cfg = do
    SiteConfig -> Rules ()
processShowcaseItems SiteConfig
cfg
    SiteConfig -> Rules ()
processShowcaseIndex SiteConfig
cfg

-- | Builds the index page, listing all projects
processShowcaseIndex :: SiteConfig -> Rules ()
processShowcaseIndex :: SiteConfig -> Rules ()
processShowcaseIndex SiteConfig
cfg =
    SiteConfig -> Page -> Rules ()
processPage SiteConfig
cfg (SiteConfig -> String -> Page
page SiteConfig
cfg String
projectsGroup){pageContext = getProjectsCtx cfg, pageTemplates = [resolveTemplate cfg "with-projects.html"]}

{- | Compiles each project (not routed), so the index can list it

The raw YAML is kept as the item; parsing here makes an invalid project fail the build.
-}
processShowcaseItems :: SiteConfig -> Rules ()
processShowcaseItems :: SiteConfig -> Rules ()
processShowcaseItems SiteConfig
cfg =
    Pattern -> Rules () -> Rules ()
match (SiteConfig -> Pattern
projectsPattern SiteConfig
cfg) (Rules () -> Rules ()) -> Rules () -> Rules ()
forall a b. (a -> b) -> a -> b
$
        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
$ do
            item <- Compiler (Item String)
getResourceString
            _ <- requireProject item
            return item

-- | Build context for the index page
getProjectsCtx :: SiteConfig -> Compiler (Context String)
getProjectsCtx :: SiteConfig -> Compiler (Context String)
getProjectsCtx SiteConfig
cfg = do
    items <- Pattern -> Compiler [Item String]
forall a. (Binary a, Typeable a) => Pattern -> Compiler [Item a]
loadAll (SiteConfig -> Pattern
projectsPattern SiteConfig
cfg)
    projects <- mapM (\Item String
item -> Identifier -> Project -> Item Project
forall a. Identifier -> a -> Item a
Item (Item String -> Identifier
forall a. Item a -> Identifier
itemIdentifier Item String
item) (Project -> Item Project)
-> Compiler Project -> Compiler (Item Project)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Item String -> Compiler Project
requireProject Item String
item) items
    let ordered = (Item Project -> (Int, Down Day))
-> [Item Project] -> [Item Project]
forall b a. Ord b => (a -> b) -> [a] -> [a]
sortOn (Project -> (Int, Down Day)
showcaseKey (Project -> (Int, Down Day))
-> (Item Project -> Project) -> Item Project -> (Int, Down Day)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Item Project -> Project
forall a. Item a -> a
itemBody) [Item Project]
projects
    return $ listField "projects" projectContext (return ordered) <> globalContext cfg