The cssMap now contains the rendered css together with its hash. That way there is no need to give a component a name, and css is rendered along the way and carried as a string.
62 lines
1.7 KiB
Haskell
62 lines
1.7 KiB
Haskell
module Components
|
|
( Prop(..)
|
|
, Component(..)
|
|
, new
|
|
, (<.>)
|
|
, addCss
|
|
, addAsset
|
|
, addAsset'
|
|
, getBody
|
|
, getCss
|
|
, getAssets
|
|
) where
|
|
|
|
import Clay ( Css )
|
|
import Core.Render ( )
|
|
import Core.Writer
|
|
import Data.Hashable ( hash )
|
|
import qualified Data.IntMap as Map
|
|
import Routes
|
|
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.IntMap String
|
|
, 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
|
|
|
|
-- |Add a name and css to a Prop.
|
|
addCss :: Css -> Component ()
|
|
addCss css = tell $ Prop (Map.singleton cssHash cssString) mempty
|
|
where
|
|
cssString = show css
|
|
cssHash = hash cssString
|
|
|
|
-- |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 body
|
|
getBody :: Component a -> a
|
|
getBody = fst . runWriter
|
|
|
|
-- |Get a Component's Css
|
|
getCss :: Component a -> String
|
|
getCss = mconcat . map snd . Map.toList . cssMap . snd . runWriter
|
|
|
|
-- |Get a Component's assets tree
|
|
getAssets :: Component a -> FileTree
|
|
getAssets = assetsTree . snd . runWriter
|