etienne-moqueur/src/Components.hs
etienne 978dffb671 Added compile rule on assets.
Assets declared throughout Components are gathered in a FileTree
structure. At compile time, the assets tree is flattened to give all
assets paths and each asset is matched and copied.
This prevents unused assets that are in the source to be deployed.
2023-06-19 22:17:20 +02:00

66 lines
2 KiB
Haskell

module Components
( Prop(..)
, prop
, Component(..)
, new
, (<.>)
, addCss
, addAsset
, addAsset'
, getHtml
, getCss
, getAssets
) where
import Clay ( Css
, compact
, renderWith
)
import Core.Writer
import qualified Data.Map as Map
import Data.Text.Lazy ( unpack )
import Routes
import Text.Blaze.Html
import Text.Blaze.Html.Renderer.String
import Utils.FileTree
-- |Props are data on top of a component's html. They are aggregated when components are combined. The choice of structures for Prop ensures that there is no duplicate at compile time (e.g. the css of a button used 5 times is only rendered once.)
data Prop = Prop
{ cssMap :: Map.Map String Css
, assetsTree :: FileTree
}
instance Semigroup Prop where
p1 <> p2 = Prop { cssMap = Map.union (cssMap p1) (cssMap p2)
, assetsTree = assetsTree p1 <> assetsTree p2
}
instance Monoid Prop where
mempty = Prop Map.empty mempty
type Component = Writer Prop
prop :: String -> Css -> Prop
prop name css = Prop (Map.singleton name css) mempty
-- |Add a name and css to a Prop.
addCss :: String -> Css -> Component ()
addCss name css = tell $ Prop (Map.singleton name css) mempty
-- |Add an asset to the Prop's tree.
addAsset :: FilePath -> Component ()
addAsset fp = tell $ Prop Map.empty (build fp)
addAsset' :: Route -> Component ()
addAsset' r = tell $ Prop Map.empty (build' r)
-- |Get a Component's Html
getHtml :: Component Html -> Html
getHtml = fst . runWriter
-- |Get a Component's Css
getCss :: Component a -> Css
getCss = mconcat . map snd . Map.toList . cssMap . snd . runWriter
-- |Get a Component's assets tree
getAssets :: Component a -> FileTree
getAssets = assetsTree . snd . runWriter