{-# LANGUAGE GADTs #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RankNTypes #-} -- | bulma divs module Reflex.Bulmex.Tag where import Control.Applicative import Data.Bool import qualified Data.Map.Strict as Map import qualified Data.Text as Text import Reflex import Reflex.Bulmex.Attr import Reflex.Bulmex.Space import qualified Reflex.Dom.Builder.Class as Dom import qualified Reflex.Dom.Widget as Dom import qualified Reflex.Tags as T container :: Dom.DomBuilder t m => m a -> m a container = containerClass mempty containerClass :: Dom.DomBuilder t m => Text.Text -> m a -> m a containerClass = partialDiv "container" partialDiv :: Dom.DomBuilder t m => Text.Text -> Text.Text -> m a -> m a partialDiv = txtEl T.divClass txtEl :: (Text.Text -> m a -> m a) -> Text.Text -> Text.Text -> m a -> m a txtEl = defaultEl spaceJoin -- | allows us to set a default value for tags by defining a join function -- not a monoid because often it does it wrong, text needs a space -- for example in case of classes, and the default map monoid is broken defaultEl :: (arg -> arg -> arg) -> (arg -> m a -> m a) -> arg -> arg -> m a -> m a defaultEl monoidF elF a b = elF $ monoidF a b buttons :: Dom.DomBuilder t m => m a -> m a buttons = T.divClass "buttons" -- | kindoff hard to set an image tag in reflex image :: Dom.DomBuilder t m => Text.Text -> m() image url = T.imgAttr (Map.singleton "src" url) Dom.blank -- | first class second src imageClass :: Dom.DomBuilder t m => Text.Text -> Text.Text -> m() imageClass clazz url = T.imgAttr (Map.fromList [("src",url), ("class", clazz)]) Dom.blank -- | bulma hero sturcture -- |
-- |
-- |
hero :: Dom.DomBuilder t m => Text.Text -> m a -> m a hero styles = txtEl T.sectionClass "hero" styles . T.divClass "hero-body" . container content :: Dom.DomBuilder t m => m a -> m a content = T.divClass "content" sect :: (Dom.DomBuilder t m) => m a -> m a sect = T.divClass "section" section :: (PostBuild t m, Dom.DomBuilder t m) => m a -> m a section = sectionDyn $ constDyn mempty sectionDyn :: (PostBuild t m, Dom.DomBuilder t m) => Dynamic t AttrMap -> m a -> m a sectionDyn = dynAttrEl (\a b -> T.divDynAttr a $ container b) $ classAttr "section" columns :: Dom.DomBuilder t m => m a -> m a columns = columnsClass mempty column :: Dom.DomBuilder t m => m a -> m a column = columnClass mempty columnsClass :: Dom.DomBuilder t m => Text.Text -> m a -> m a columnsClass = partialDiv "columns" columnClass :: Dom.DomBuilder t m => Text.Text -> m a -> m a columnClass = partialDiv "column" control :: Dom.DomBuilder t m => m a -> m a control = controlClass mempty controlClass :: Dom.DomBuilder t m => Text.Text -> m a -> m a controlClass = partialDiv "control" controlDyn :: (PostBuild t m, Dom.DomBuilder t m) => Dynamic t AttrMap -> m a -> m a controlDyn = dynAttrEl T.divDynAttr $ classAttr "control" tile :: Dom.DomBuilder t m => Text.Text -> m a -> m a tile = partialDiv "tile" tileChild :: Dom.DomBuilder t m => m a -> m a tileChild = tileChildClass mempty tileChildClass :: Dom.DomBuilder t m => Text.Text -> m a -> m a tileChildClass = txtEl tile "is-child" tileParentClass :: Dom.DomBuilder t m => Text.Text -> m a -> m a tileParentClass = txtEl tile "is-parent" tileParent :: Dom.DomBuilder t m => m a -> m a tileParent = tileParentClass mempty tileAncestor :: Dom.DomBuilder t m => m a -> m a tileAncestor = tile "is-ancestor" dynAttrEl :: Reflex t => (Dynamic t AttrMap -> m a -> m a) -> AttrMap -> Dynamic t AttrMap -> m a -> m a dynAttrEl f = defaultEl ((<*>) . (<$>) attrUnion) f . constDyn field :: Dom.DomBuilder t m => m a -> m a field = fieldClass mempty fieldClass :: Dom.DomBuilder t m => Text.Text -> m a -> m a fieldClass = partialDiv "field" fieldGrouped :: Dom.DomBuilder t m => m a -> m a fieldGrouped = fieldClass "is-grouped" title :: Dom.DomBuilder t m => m a -> m a title = titleClazz "is-1" titleClazz :: Dom.DomBuilder t m => Text.Text -> m a -> m a titleClazz = txtEl T.h1Class "title" subtitle :: Dom.DomBuilder t m => m a -> m a subtitle = subtitleClass "is-3" subtitleClass :: Dom.DomBuilder t m => Text.Text -> m a -> m a subtitleClass = txtEl T.h2Class "subtitle" box :: Dom.DomBuilder t m => m a -> m a box = T.divClass "box" evtText :: (Dom.DomBuilder t m, PostBuild t m, MonadHold t m) => Event t Text.Text -> m () evtText evt = Dom.dynText =<< holdDyn "" evt labeled' :: Dom.DomBuilder t m => m () -> m a -> m a labeled' labelM inputM = do labelEl labelM control inputM -- | named labelEl cause didn't want to fix name clashes labelEl :: Dom.DomBuilder t m => m a -> m a labelEl = labelClass mempty labelClass :: Dom.DomBuilder t m => Text.Text -> m a -> m a labelClass = txtEl T.labelClass "label" data ToolDirection = Top -- top is graphic bugged | Lft | Rght | Down -- | balloon css, for example: https://cdnjs.cloudflare.com/ajax/libs/balloon-css/0.5.0/balloon.min.css tooltipText :: (PostBuild t m, Dom.DomBuilder t m) => Dynamic t Text.Text -> m a -> m a tooltipText = tooltipText' Rght tooltipText' :: (PostBuild t m, Dom.DomBuilder t m) => ToolDirection -> Dynamic t Text.Text -> m a -> m a tooltipText' dir tipDyn monad = T.spanDynAttr (tipToAttr dir <$> tipDyn) $ monad tipToAttr :: ToolDirection -> Text.Text -> AttrMap tipToAttr dir "" = tipToAttr dir "-" tipToAttr dir tip = Map.fromList [("data-balloon", tip), ("data-balloon-pos", direction dir)] direction :: ToolDirection -> Text.Text direction Top = "top" direction Lft = "left" direction Rght = "right" direction Down = "down" icon :: (PostBuild t m, Dom.DomBuilder t m) => Text.Text -> m () icon = iconClass "" -- | second is name iconClass :: (PostBuild t m, Dom.DomBuilder t m) => Text.Text -> Text.Text -> m () iconClass wrapClass = iconDyn (constDyn (classAttr wrapClass)) . constDyn . classAttr iconDyn :: (PostBuild t m, Dom.DomBuilder t m) => Dynamic t AttrMap -> Dynamic t AttrMap -> m () iconDyn wrapClass mdiClass = do textSpace T.spanDynAttr (attrUnion (classAttr "icon") <$> wrapClass) $ T.iDynAttr (Map.unionWith (<>) (classAttr "mdi mdi-") <$> mdiClass) $ Dom.blank textSpace -- | sometimes you just need 2 pieces of text to seperate with a space textSpace :: Dom.DomBuilder t m => m () textSpace = Dom.text space flask :: (PostBuild t m, Dom.DomBuilder t m) => m () flask = icon "flask" -- | a html tag that accepts any text into it's href value ahref :: (Dom.DomBuilder t m, PostBuild t m) => Text.Text -> m a -> m a ahref = ahref' mempty ahref' :: (Dom.DomBuilder t m, PostBuild t m) => AttrMap -> Text.Text -> m a -> m a ahref' uno = ahrefDyn (constDyn uno) . constDyn ahrefDyn :: (Dom.DomBuilder t m, PostBuild t m) => Dynamic t AttrMap -> Dynamic t Text.Text -> m a -> m a ahrefDyn uno txt = T.aDynAttr $ (attrUnion <$> uno) <*> (Map.singleton "href" <$> txt) switchDiv :: (PostBuild t m, Dom.DomBuilder t m) => Dynamic t Bool -> m () -> m a -> m a switchDiv attrDyn true false = do hideDiv_ (not <$> attrDyn) true hideDiv_ attrDyn false -- | when dynamic is true ishidden will be added, else the attrmap is used hideDiv :: (PostBuild t m, Dom.DomBuilder t m) => Dynamic t AttrMap -> Dynamic t Bool -> m a -> m a hideDiv attrDyn hide = T.divDynAttr $ bool <$> attrDyn <*> constDyn isHidden <*> hide hideDiv_ :: (PostBuild t m, Dom.DomBuilder t m) => Dynamic t Bool -> m a -> m a hideDiv_ = hideDiv $ constDyn Map.empty loadSpinner :: (Dom.DomBuilder t m) => m () loadSpinner = imageClass "loadSpinner" "spinner.svg" hideEmptyDiv :: (Eq (f b), Alternative f, PostBuild t m, Dom.DomBuilder t m) => Dynamic t (f b) -> m a -> m a hideEmptyDiv = hideEmptyDyn $ constDyn Map.empty hideEmptyDyn :: (Eq (f b), Alternative f, PostBuild t m, Dom.DomBuilder t m) => Dynamic t AttrMap -> Dynamic t (f b) -> m a -> m a hideEmptyDyn dyn = hideDiv dyn . fmap ((==) empty)