aboutsummaryrefslogtreecommitdiff
path: root/client/src/Component/Modal.hs
diff options
context:
space:
mode:
Diffstat (limited to 'client/src/Component/Modal.hs')
-rw-r--r--client/src/Component/Modal.hs117
1 files changed, 117 insertions, 0 deletions
diff --git a/client/src/Component/Modal.hs b/client/src/Component/Modal.hs
new file mode 100644
index 0000000..46d3f64
--- /dev/null
+++ b/client/src/Component/Modal.hs
@@ -0,0 +1,117 @@
+module Component.Modal
+ ( In(..)
+ , Content
+ , view
+ ) where
+
+import Control.Monad (void)
+import qualified Data.Map as M
+import qualified Data.Map.Lazy as LM
+import Data.Text (Text)
+import qualified Data.Text as T
+import Data.Time.Clock (NominalDiffTime)
+import qualified GHCJS.DOM.Element as Element
+import qualified GHCJS.DOM.Node as Node
+import JSDOM.Types (JSString)
+import Reflex.Dom (Dynamic, Event, MonadWidget)
+import qualified Reflex.Dom as R
+import qualified Reflex.Dom.Class as R
+
+import qualified Util.Reflex as ReflexUtil
+
+-- Content = CurtainClickEvent -> (CancelEvent, ConfirmEvent)
+type Content t m = Event t () -> m (Event t (), Event t ())
+
+data In t m = In
+ { _in_show :: Event t ()
+ , _in_content :: Content t m
+ }
+
+view :: forall t m a. MonadWidget t m => In t m -> m (Event t ())
+view input = do
+ rec
+ let show = Show <$ (_in_show input)
+
+ startHiding =
+ R.attachWithMaybe
+ (\a _ -> if a then Just StartHiding else Nothing)
+ (R.current canBeHidden)
+ (R.leftmost [ hide, curtainClick ])
+
+ canBeHidden <-
+ R.holdDyn True $ R.leftmost
+ [ False <$ startHiding
+ , True <$ endHiding
+ ]
+
+ endHiding <-
+ R.delay (0.2 :: NominalDiffTime) (EndHiding <$ startHiding)
+
+ let action =
+ R.leftmost [ show, startHiding, endHiding ]
+
+ modalClass <-
+ R.holdDyn "" (fmap getModalClass action)
+
+ (elem, dyn) <-
+ R.buildElement "div" (getAttributes <$> modalClass) $
+ ReflexUtil.visibleIfEvent
+ (isVisible <$> action)
+ (R.blank >> return (R.never, R.never, R.never))
+ (do
+ (curtain, _) <- R.elAttr' "div" (M.singleton "class" "g-Modal__Curtain") $ R.blank
+ let curtainClick = R.domEvent R.Click curtain
+ (hide, content) <- R.divClass "g-Modal__Content" (_in_content input curtainClick)
+ return (curtainClick, hide, content))
+
+
+ performShowEffects action elem
+
+ let curtainClick = R.switchDyn $ (\(a, _, _) -> a) <$> dyn
+ let hide = R.switchDyn $ (\(_, b, _) -> b) <$> dyn
+ let content = R.switchDyn $ (\(_, _, c) -> c) <$> dyn
+
+ -- Delay the event in order to let time for the modal to disappear
+ R.delay (0.5 :: NominalDiffTime) content
+
+getAttributes :: Text -> LM.Map Text Text
+getAttributes modalClass =
+ M.singleton "class" $
+ T.intercalate " " [ "g-Modal", modalClass]
+
+performShowEffects
+ :: forall t m a. MonadWidget t m
+ => Event t Action
+ -> Element.Element
+ -> m ()
+performShowEffects showEvent elem = do
+ body <- ReflexUtil.getBody
+
+ let showEffects =
+ flip fmap showEvent (\case
+ Show -> do
+ Node.appendChild body elem
+ Element.setClassName body ("g-Body--Modal" :: JSString)
+ StartHiding ->
+ return ()
+ EndHiding -> do
+ Node.removeChild body elem
+ Element.setClassName body ("" :: JSString)
+ )
+
+ R.performEvent_ $ void `fmap` showEffects
+
+data Action
+ = Show
+ | StartHiding
+ | EndHiding
+
+getModalClass :: Action -> Text
+getModalClass Show = "g-Modal--Show"
+getModalClass StartHiding = "g-Modal--Hiding"
+getModalClass _ = ""
+
+isVisible :: Action -> Bool
+isVisible Show = True
+isVisible StartHiding = True
+isVisible EndHiding = False