module Slab.Render
( prettyHtmls
, renderHtmls
, renderBlocks
) where
import Data.String (fromString)
import Data.Text (Text)
import Data.Text qualified as T
import Data.Text.Lazy qualified as TL
import Slab.Syntax qualified as Syntax
import Text.Blaze.Html.Renderer.Pretty qualified as Pretty (renderHtml)
import Text.Blaze.Html.Renderer.Text (renderHtml)
import Text.Blaze.Html5 (Html, (!))
import Text.Blaze.Html5 qualified as H
import Text.Blaze.Html5.Attributes qualified as A
import Text.Blaze.Svg11 qualified as S
--------------------------------------------------------------------------------
prettyHtmls :: [Html] -> Text
prettyHtmls = T.pack . concat . map Pretty.renderHtml
renderHtmls :: [Html] -> TL.Text
renderHtmls = TL.concat . map renderHtml
--------------------------------------------------------------------------------
renderBlocks :: [Syntax.Block] -> [H.Html]
renderBlocks = map renderBlock
renderBlock :: Syntax.Block -> H.Html
renderBlock Syntax.BlockDoctype = H.docType
renderBlock (Syntax.BlockElem name mdot attrs children) =
mAddAttrs $
mAddId $
mAddClass $
renderElem name $
mconcat $
if mdot == Syntax.HasDot
then [renderTexts children]
else map renderBlock children
where
mAddId :: H.Html -> H.Html
mAddId e =
if idNames == []
then e
else e ! A.id (H.toValue idNames')
idNames = Syntax.idNamesFromAttrs attrs
idNames' :: Text
idNames' = T.intercalate "-" idNames -- TODO Refuse multiple Ids in some kind of validation step after parsing ?
mAddClass :: H.Html -> H.Html
mAddClass e =
if classNames == []
then e
else e ! A.class_ (H.toValue classNames')
classNames = Syntax.classNamesFromAttrs attrs
classNames' :: Text
classNames' = T.intercalate " " classNames
mAddAttrs :: H.Html -> H.Html
mAddAttrs =
flip (foldl (\e (a, b) -> e ! H.customAttribute (fromString $ T.unpack a) (H.toValue b))) attrs'
attrs' = Syntax.namesFromAttrs attrs
renderBlock (Syntax.BlockText _ []) =
H.preEscapedText "\n" -- This allows to force some whitespace.
renderBlock (Syntax.BlockText _ [Syntax.Lit s])
| s == T.empty = H.preEscapedText "\n" -- This allows to force some whitespace.
| otherwise = H.preEscapedText s -- TODO
renderBlock (Syntax.BlockText _ _) = error "Template is not rendered."
renderBlock (Syntax.BlockInclude (Just "escape-html") _ (Just nodes)) =
escapeTexts nodes
renderBlock (Syntax.BlockInclude _ _ (Just nodes)) = mapM_ renderBlock nodes
renderBlock (Syntax.BlockInclude _ path Nothing) = H.stringComment $ "include " <> path
renderBlock (Syntax.BlockFragmentDef _ _ _) = mempty
renderBlock (Syntax.BlockFragmentCall _ _ nodes) = mapM_ renderBlock nodes
renderBlock (Syntax.BlockFor _ _ _ nodes) = mapM_ renderBlock nodes
renderBlock (Syntax.BlockComment b content) =
case b of
Syntax.PassthroughComment -> H.textComment content
Syntax.NormalComment -> mempty
renderBlock (Syntax.BlockFilter "escape-html" content) =
H.text content
renderBlock (Syntax.BlockFilter name _) = error $ "Unknown filter name " <> T.unpack name
renderBlock (Syntax.BlockRawElem content children) = do
H.preEscapedText content -- TODO Construct a proper tag ?
mapM_ renderBlock children
renderBlock (Syntax.BlockDefault _ nodes) = mapM_ renderBlock nodes
renderBlock (Syntax.BlockImport _ (Just nodes) _) = mapM_ renderBlock nodes
renderBlock (Syntax.BlockRun _ (Just nodes)) = mapM_ renderBlock nodes
renderBlock (Syntax.BlockRun cmd _) = H.textComment $ "run " <> cmd
renderBlock (Syntax.BlockImport path Nothing _) = H.stringComment $ "extends " <> path
renderBlock (Syntax.BlockReadJson _ _ _) = mempty
renderBlock (Syntax.BlockAssignVar _ _) = mempty
renderBlock (Syntax.BlockIf _ as bs) = do
-- The evaluation code transforms a BlockIf into a BlockList, so this should
-- not be called.
mapM_ renderBlock as
mapM_ renderBlock bs
renderBlock (Syntax.BlockList nodes) =
mapM_ renderBlock nodes
renderBlock (Syntax.BlockCode (Syntax.SingleQuoteString s))
| s == T.empty = mempty
| otherwise = H.text s -- Should be already escaped in the AST ?
renderBlock (Syntax.BlockCode (Syntax.Variable s)) =
H.textComment $ "code variable " <> s
renderBlock (Syntax.BlockCode (Syntax.Int i)) =
H.string $ show i
renderBlock (Syntax.BlockCode (Syntax.Object _)) =
H.text "