Commit a96dab75 authored by arturo's avatar arturo

>>> continue

parent 5ef89cff
module Gargantext.Components.Bootstrap.Cloak
( cloak
) where
import Gargantext.Prelude
import Data.Foldable (elem)
import Data.Maybe (Maybe, fromMaybe)
import Data.Tuple.Nested ((/\))
import Effect.Timer (setTimeout)
import Gargantext.Utils.Reactix as R2
import Reactix as R
import Toestand as T
type Props =
( defaultSlot :: R.Element
, cloakSlot :: R.Element
, isDisplayed :: Boolean
, idlingPhaseDuration :: Maybe Int -- Milliseconds
, sustainingPhaseDuration :: Maybe Int -- Milliseconds
)
-- | Abstract component type easing the transition display between a content
-- | component and transitional (or cloak) component
-- |
-- |
-- | Inputs:
-- | * `defaultSlot :: Element` transclude pattern providing elements
-- | to be finally displayed
-- | * `cloakSlot :: Element` transclude pattern proviging elements
-- | displayed during first phases (see lifecycle explanation below)
-- | * `isDisplayed :: Boolean` flag defining if the main content is
-- | ready to be displayed
-- | * `idlingPhaseDuration :: Maybe Int` if defined, perform idling
-- | phase (see lifecyle explanation below)
-- | * `sustainingPhaseDuration :: Maybe Int` if defined, perform sustaining
-- | phase (see lifecyle explanation below)
-- |
-- |
-- | The lifecycle is structured into 4 phases:
-- | 1. OPTIONAL, a primary idle phase, where no component is being displayed
-- | ↳ why? if the flag switched from "off" to "on" in a particularly fast
-- | pace, it will jump the sustain and wait phases (ie. the display
-- | of the transitional component, see below) which won't be
-- [ needed anymore
-- | 2. OPTIONAL a sustain phase, where the transitional component will be
-- | displayed for a defined amount of time
-- | ↳ why? same heuristic as above, if the switch is too fast, the cloak
-- | will be displayed at such speed that it will create a flickering
-- | effect, this phase will avoid it
-- | 3. a waiting phase, where the cloak will be displayed until the switch
-- | will be set to "on"
-- | 4. a final display phase, where the main content component will be shown
-- |
-- |
-- | Simple transition:
-- |
-- | ```purescript
-- | cloak
-- | { isDisplayed : onPendingFlag
-- | , cloakSlot : blankPlaceholder {}
-- | , defaultSlot : componentToBeDisplayed {} []
-- | , idlingPhaseDuration : Nothing
-- | , sustainingPhaseDuration : Nothing
-- | }
-- | ```
-- |
-- |
-- | Smart transition
-- |
-- | ```purescript
-- | cloak
-- | { isDisplayed : onPendingFlag
-- | , cloakSlot : blankPlaceholder {}
-- | , defaultSlot : componentToBeDisplayed {} []
-- | -- Idling phase set up
-- | --
-- | -- * if the computation for display makes less than 20ms, no
-- | -- transition at all will be displayed, and the content will arrive
-- | -- as soon as the 20ms delay is consumed
-- | -- * if the computation takes more, following phases will be set up
-- | -- (according to the configuration provided)
-- | , idlingPhaseDuration : Just 20
-- | -- Sustaining phase set up
-- | --
-- | -- * now let's say the computation talking above makes 35ms before
-- | -- displaying its content, setting this parameter will avoid a:
-- | -- 35ms (computation) - 20ms (idling) = 15ms (sustaining)
-- | -- * this very short delay will be considered as a UI flickering
-- | -- effect for the user, which is a UX smelly design
-- | -- * by setting the sustaining phase to 400ms, we ensure a period
-- | -- of time that eliminates this effect
-- | , sustainingPhaseDuration : Just 400
-- | }
-- | ```
cloak :: R2.Leaf Props
cloak = R2.leaf component
cname :: String
cname = "b-cloak"
component :: R.Component Props
component = R.hooksComponent cname cpt where
cpt props _ = do
-- State
phase /\ phaseBox <- R2.useBox' (Idle :: Phase)
-- Computed
canCloakBeDisplayed <- pure $ elem phase [ Sustain, Wait ]
canContentBeDisplayed <- pure $ elem phase [ Display ]
-- @executeDisplayingPhase
execDisplayingPhase <- pure $ const $
T.write_ Display phaseBox
-- Helpers
execDisplayingPhaseOr <- pure $ \fn ->
if props.isDisplayed
then execDisplayingPhase unit
else fn
-- @executeWaitingPhase
execWaitingPhase <- pure $ const $ execDisplayingPhaseOr $
T.write_ Wait phaseBox
-- @executeSustainingPhase
execSustainingPhase <- pure $ const $ execDisplayingPhaseOr $
T.write_ Sustain phaseBox
<* setTimeout
(fromMaybe 0 props.sustainingPhaseDuration)
(execWaitingPhase unit)
-- @executeIdlingPhase
execIdlingPhase <- pure $ const $ execDisplayingPhaseOr $
T.write_ Idle phaseBox
<* setTimeout
(fromMaybe 0 props.idlingPhaseDuration)
(execSustainingPhase unit)
-- Effects
R.useEffectOnce' $ execIdlingPhase unit
R.useEffect1' props.isDisplayed $
if (props.isDisplayed && phase == Wait)
then execDisplayingPhase unit
else pure unit
-- Render
pure $
R.fragment
[
R2.if' canCloakBeDisplayed props.cloakSlot
,
R2.if' canContentBeDisplayed props.defaultSlot
]
data Phase =
Idle
| Sustain
| Wait
| Display
derive instance eqPhase :: Eq Phase
...@@ -4,6 +4,7 @@ module Gargantext.Components.Bootstrap ...@@ -4,6 +4,7 @@ module Gargantext.Components.Bootstrap
import Gargantext.Components.Bootstrap.BaseModal(baseModal) as Exports import Gargantext.Components.Bootstrap.BaseModal(baseModal) as Exports
import Gargantext.Components.Bootstrap.Button(button) as Exports import Gargantext.Components.Bootstrap.Button(button) as Exports
import Gargantext.Components.Bootstrap.Cloak(cloak) as Exports
import Gargantext.Components.Bootstrap.Div(div', div_) as Exports import Gargantext.Components.Bootstrap.Div(div', div_) as Exports
import Gargantext.Components.Bootstrap.FormInput(formInput) as Exports import Gargantext.Components.Bootstrap.FormInput(formInput) as Exports
import Gargantext.Components.Bootstrap.FormSelect(formSelect) as Exports import Gargantext.Components.Bootstrap.FormSelect(formSelect) as Exports
......
...@@ -160,18 +160,13 @@ setGlobalD3Reference window d3 = void $ pure $ (window .= "d3") d3 ...@@ -160,18 +160,13 @@ setGlobalD3Reference window d3 = void $ pure $ (window .= "d3") d3
onPhyloReady :: Document -> String -> Effect Unit onPhyloReady :: Document -> String -> Effect Unit
onPhyloReady d s = do onPhyloReady d s = do
-- Unhide some elements turnVisible `toElements` "#phyloToolBar"
setText s `toElements` "#phyloName"
turnVisible `toElements` "#phyloName"
turnVisible `toElements` "#phyloTopBar" turnVisible `toElements` "#phyloTopBar"
turnVisible `toElements` ".reset" turnVisible `toElements` ".reset"
turnVisible `toElements` ".label" turnVisible `toElements` ".label"
turnVisible `toElements` ".heading" turnVisible `toElements` ".heading"
turnVisible `toElements` ".export" turnVisible `toElements` ".export"
-- Draw the search box
where where
toElements fn query = querySelectorAll d query >>= flip for_ fn toElements fn query = querySelectorAll d query >>= flip for_ fn
...@@ -179,8 +174,6 @@ onPhyloReady d s = do ...@@ -179,8 +174,6 @@ onPhyloReady d s = do
style <- pure $ (el .. "style") style <- pure $ (el .. "style")
pure $ (style .= "visibility") "visible" pure $ (style .= "visibility") "visible"
setText name el = pure $ (el .= "innerHTML") name
----------------------------------------------------------- -----------------------------------------------------------
highlightSource :: Window -> String -> Effect Unit highlightSource :: Window -> String -> Effect Unit
......
...@@ -7,6 +7,7 @@ import Gargantext.Prelude ...@@ -7,6 +7,7 @@ import Gargantext.Prelude
import DOM.Simple (document, window) import DOM.Simple (document, window)
import Data.Tuple.Nested ((/\)) import Data.Tuple.Nested ((/\))
import FFI.Simple ((..)) import FFI.Simple ((..))
import Gargantext.Components.Bootstrap as B
import Gargantext.Components.PhyloExplorer.Draw (autocompleteSearch, autocompleteSubmit, drawPhylo, highlightSource, onPhyloReady, setGlobalD3Reference, setGlobalDependencies) import Gargantext.Components.PhyloExplorer.Draw (autocompleteSearch, autocompleteSubmit, drawPhylo, highlightSource, onPhyloReady, setGlobalD3Reference, setGlobalDependencies)
import Gargantext.Components.PhyloExplorer.TopBar (topBar) import Gargantext.Components.PhyloExplorer.TopBar (topBar)
import Gargantext.Components.PhyloExplorer.Types (GlobalTerm, PhyloDataSet(..), Source, sortSources) import Gargantext.Components.PhyloExplorer.Types (GlobalTerm, PhyloDataSet(..), Source, sortSources)
...@@ -31,13 +32,12 @@ layoutCpt = here.component "layout" cpt where ...@@ -31,13 +32,12 @@ layoutCpt = here.component "layout" cpt where
cpt { phyloDataSet: (PhyloDataSet o) cpt { phyloDataSet: (PhyloDataSet o)
} _ = do } _ = do
-- States -- States
isDisplayed /\ isReadyBox <- R2.useBox' false
mTopBarHost <- R.unsafeHooksEffect $ R2.getElementById "portal-topbar"
sources /\ sourcesBox <- R2.useBox' (mempty :: Array Source) sources /\ sourcesBox <- R2.useBox' (mempty :: Array Source)
-- @WIP: move value to PhyloDataSet?
-- @WIP: move vale to PhyloDataSet?
terms /\ termsBox <- R2.useBox' (mempty :: Array GlobalTerm) terms /\ termsBox <- R2.useBox' (mempty :: Array GlobalTerm)
mTopBarHost <- R.unsafeHooksEffect $ R2.getElementById "portal-topbar"
R.useEffectOnce' $ do R.useEffectOnce' $ do
(sortSources >>> flip T.write_ sourcesBox) o.sources (sortSources >>> flip T.write_ sourcesBox) o.sources
setGlobalD3Reference window d3 setGlobalD3Reference window d3
...@@ -51,174 +51,149 @@ layoutCpt = here.component "layout" cpt where ...@@ -51,174 +51,149 @@ layoutCpt = here.component "layout" cpt where
o.branchLinks o.branchLinks
o.bb o.bb
onPhyloReady document o.name onPhyloReady document o.name
T.write_ true isReadyBox
-- @WIP: handling global variables -- @WIP: handling global variables
T.write_ (window .. "terms") termsBox T.write_ (window .. "terms") termsBox
-- Render -- Render
pure $ pure $
H.div H.div
{ className: "phylo" } { className: "phylo" }
[ [
R2.if' (not isDisplayed) $
B.spinner
-- <!-- row 1 --> { className: "phylo__spinner" }
H.div
{ className: "phylo-title font-bold" }
[ H.text "Mèmiescape" ]
, ,
H.div R.fragment
{ className: "phylo-folder" }
[
-- <!-- title bar (static mode) -->
H.label
{ id: "phyloName"
, className: "phylo-name"
}
[]
]
,
-- <!-- row 2 & 3 -->
phyloCorpus {} []
,
phyloCorpusInfo
{ nbDocs : o.nbDocs
, nbFoundations : o.nbFoundations
, nbPeriods : o.nbPeriods
}
[]
,
phyloHow {} []
,
phyloPhylo {} []
,
phyloPhyloInfo
{ nbTerms : o.nbTerms
, nbGroups : o.nbGroups
, nbBranches : o.nbBranches
}
[]
,
H.div
{ id: "phyloIsoLine"
, className: "phylo-isoline"
}
[]
,
H.div
{ id: "phyloIsolineInfo"
, className: "phylo-isoline-info"
}
[ [
-- Phylo Tool Bar
H.div H.div
{ className: "btn-group" } { id: "phyloToolBar"
, style: { visibility: "hidden" } }
[ [
H.button phyloCorpusInfo
{ id: "reset" { nbDocs : o.nbDocs
, className: "button reset" , nbFoundations : o.nbFoundations
, nbPeriods : o.nbPeriods
} }
[
H.i
{ className: "fa fa-arrows-alt" }
[]
]
, ,
H.button phyloHow
{ id: "label" {}
, className: "button label"
}
[
H.i
{ className: "fa fa-dot-circle-o" }
[]
]
, ,
H.button phyloPhylo
{ id: "heading" {}
, className: "button heading"
}
[
H.i
{ className: "fa fa-sort-alpha-asc" }
[]
]
, ,
H.button phyloPhyloInfo
{ id: "export" { nbTerms : o.nbTerms
, className: "button export" , nbGroups : o.nbGroups
, nbBranches : o.nbBranches
} }
]
,
-- <!-- row 2 & 3 -->
H.div
{ id: "phyloIsoLine"
, className: "phylo-isoline"
}
[]
,
H.div
{ id: "phyloIsolineInfo"
, className: "phylo-isoline-info"
}
[
H.div
{ className: "btn-group" }
[ [
H.i H.button
{ className: "fas fa-camera" } { id: "reset"
[] , className: "button reset"
}
[
H.i
{ className: "fa fa-arrows-alt" }
[]
]
,
H.button
{ id: "label"
, className: "button label"
}
[
H.i
{ className: "fa fa-dot-circle-o" }
[]
]
,
H.button
{ id: "heading"
, className: "button heading"
}
[
H.i
{ className: "fa fa-sort-alpha-asc" }
[]
]
,
H.button
{ id: "export"
, className: "button export"
}
[
H.i
{ className: "fas fa-camera" }
[]
]
] ]
] ]
] ,
,
-- <!-- row 4 -->
H.div
{ id: "phyloScape"
, className: "phylo-scape"
}
[]
,
H.div
{ id: "phyloTimeline"
, className: "phylo-timeline"
}
[]
,
H.div
{ id: "phyloGraph"
, className: "phylo-graph"
}
[]
, -- <!-- row 4 -->
-- <!-- PORTAL: topbar --> H.div
R2.createPortal' mTopBarHost { id: "phyloScape"
[ , className: "phylo-scape"
}
[]
,
H.div H.div
{ id: "phyloTopBar" { id: "phyloTimeline"
-- , visibility: "hidden" , className: "phylo-timeline"
} }
[]
,
H.div
{ id: "phyloGraph"
, className: "phylo-graph"
}
[]
,
-- <!-- PORTAL: topbar -->
R2.createPortal' mTopBarHost
[ [
topBar H.div
{ sourceList: sources { id: "phyloTopBar"
, sourceCallback: highlightSource window , style: { visibility: "hidden" }
, autocompleteSearchCallback: autocompleteSearch terms
, autocompleteSubmitCallback: autocompleteSubmit
} }
[
topBar
{ sourceList: sources
, sourceCallback: highlightSource window
, autocompleteSearchCallback: autocompleteSearch terms
, autocompleteSubmitCallback: autocompleteSubmit
}
]
] ]
] ]
] ]
--------------------------------------------------------
phyloCorpus :: R2.Component ()
phyloCorpus = R.createElement phyloCorpusCpt
phyloCorpusCpt :: R.Component ()
phyloCorpusCpt = here.component "phyloCorpus" cpt where
cpt _ _ = do
-- Render
pure $
H.div
{ id: "phyloCorpus"
, className: "phylo-corpus"
}
[ H.text "corpus" ]
--------------------------------------------------------- ---------------------------------------------------------
phyloHow :: R2.Component () phyloHow :: R2.Leaf ()
phyloHow = R.createElement phyloHowCpt phyloHow = R2.leaf phyloHowCpt
phyloHowCpt :: R.Component () phyloHowCpt :: R.Component ()
phyloHowCpt = here.component "phyloHow" cpt where phyloHowCpt = here.component "phyloHow" cpt where
cpt _ _ = do cpt _ _ = do
...@@ -256,8 +231,8 @@ phyloHowCpt = here.component "phyloHow" cpt where ...@@ -256,8 +231,8 @@ phyloHowCpt = here.component "phyloHow" cpt where
--------------------------------------------------------- ---------------------------------------------------------
phyloPhylo :: R2.Component () phyloPhylo :: R2.Leaf ()
phyloPhylo = R.createElement phyloPhyloCpt phyloPhylo = R2.leaf phyloPhyloCpt
phyloPhyloCpt :: R.Component () phyloPhyloCpt :: R.Component ()
phyloPhyloCpt = here.component "phyloPhylo" cpt where phyloPhyloCpt = here.component "phyloPhylo" cpt where
cpt _ _ = do cpt _ _ = do
...@@ -279,8 +254,8 @@ type PhyloCorpusInfoProps = ...@@ -279,8 +254,8 @@ type PhyloCorpusInfoProps =
, nbPeriods :: Int , nbPeriods :: Int
) )
phyloCorpusInfo :: R2.Component PhyloCorpusInfoProps phyloCorpusInfo :: R2.Leaf PhyloCorpusInfoProps
phyloCorpusInfo = R.createElement phyloCorpusInfoCpt phyloCorpusInfo = R2.leaf phyloCorpusInfoCpt
phyloCorpusInfoCpt :: R.Component PhyloCorpusInfoProps phyloCorpusInfoCpt :: R.Component PhyloCorpusInfoProps
phyloCorpusInfoCpt = here.component "phyloCorpusInfo" cpt where phyloCorpusInfoCpt = here.component "phyloCorpusInfo" cpt where
cpt props _ = do cpt props _ = do
...@@ -323,8 +298,8 @@ type PhyloPhyloInfoProps = ...@@ -323,8 +298,8 @@ type PhyloPhyloInfoProps =
, nbBranches :: Int , nbBranches :: Int
) )
phyloPhyloInfo :: R2.Component PhyloPhyloInfoProps phyloPhyloInfo :: R2.Leaf PhyloPhyloInfoProps
phyloPhyloInfo = R.createElement phyloPhyloInfoCpt phyloPhyloInfo = R2.leaf phyloPhyloInfoCpt
phyloPhyloInfoCpt :: R.Component PhyloPhyloInfoProps phyloPhyloInfoCpt :: R.Component PhyloPhyloInfoProps
phyloPhyloInfoCpt = here.component "phyloPhyloInfo" cpt where phyloPhyloInfoCpt = here.component "phyloPhyloInfo" cpt where
cpt props _ = do cpt props _ = do
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment