Home.purs 15.4 KB
Newer Older
1
module Gargantext.Components.Nodes.Home where
2

3 4
import Gargantext.Prelude

5
import Data.Array as Array
6
import Data.Maybe (Maybe(..))
7
import Data.Newtype (class Newtype)
8
import Effect (Effect)
9
import Gargantext.AsyncTasks as GAT
10
import Gargantext.Components.Data.Landing (BlockText(..), BlockTexts(..), Button(..), LandingData(..))
11
import Gargantext.Components.FolderView as FV
12 13 14
import Gargantext.Components.Lang (LandingLang(..))
import Gargantext.Components.Lang.Landing.EnUS as En
import Gargantext.Components.Lang.Landing.FrFR as Fr
15
import Gargantext.Components.Nodes.Home.Public (renderPublic)
16
import Gargantext.Config as Config
Karen Konou's avatar
Karen Konou committed
17
import Gargantext.Ends (Backend(..))
18
import Gargantext.License (license)
James Laver's avatar
James Laver committed
19
import Gargantext.Sessions (Sessions)
Alexandre Delanoë's avatar
Alexandre Delanoë committed
20
import Gargantext.Sessions as Sessions
21
import Gargantext.Sessions.Types (Session(..))
22
import Gargantext.Utils.Reactix as R2
23 24 25 26
import Reactix as R
import Reactix.DOM.HTML as H
import Routing.Hash (setHash)
import Toestand as T
27
import Gargantext.Utils.Toestand as T2
28

James Laver's avatar
James Laver committed
29 30
here :: R2.Here
here = R2.here "Gargantext.Components.Nodes.Home"
31

James Laver's avatar
James Laver committed
32
newtype State = State { userName :: String, password :: String }
33

34
derive instance Newtype State _
35 36

initialState :: State
James Laver's avatar
James Laver committed
37
initialState = State { userName: "", password: "" }
38 39 40 41 42 43 44 45 46 47 48 49 50

data Action
  = Documentation
  | Enter
  | Login
  | SignUp

performAction :: Action -> Effect Unit
performAction Documentation = pure unit
performAction Enter = void $ setHash "/search"
performAction Login = void $ setHash "/login"
performAction SignUp = pure unit

51 52 53
langLandingData :: LandingLang -> LandingData
langLandingData LL_FR = Fr.landingData
langLandingData LL_EN = En.landingData
54 55 56

------------------------------------------------------------------------

James Laver's avatar
James Laver committed
57
type HomeProps s l =
58 59
  ( backend :: T.Box (Maybe Backend)
  , lang      :: LandingLang
James Laver's avatar
James Laver committed
60 61
  , sessions  :: s
  , showLogin :: l
62
  , tasks     :: T.Box GAT.Storage
63
  , reloadForest :: T.Box T2.Reload
James Laver's avatar
James Laver committed
64
  )
65

James Laver's avatar
James Laver committed
66 67
homeLayout :: forall s l. T.Read s Sessions => T.ReadWrite l Boolean
           => R2.Leaf (HomeProps s l)
68
homeLayout props = R.createElement homeLayoutCpt props []
James Laver's avatar
James Laver committed
69 70 71
homeLayoutCpt :: forall s l. T.Read s Sessions => T.ReadWrite l Boolean
             => R.Component (HomeProps s l)
homeLayoutCpt = here.component "homeLayout" cpt
72
  where
73
    cpt { backend, lang, sessions, showLogin, tasks, reloadForest} _ = do
74
      backend' <- T.useLive T.unequal backend
James Laver's avatar
James Laver committed
75
      sessions' <- T.useLive T.unequal sessions
76
      let landingData = langLandingData lang
James Laver's avatar
James Laver committed
77 78 79 80 81
      pure $
        H.span {}
        [ H.div { className: "home-title container1" }
          [ jumboTitle landingData ]
        , H.div { className: "home-research-form container1" } [] -- TODO
82
        , joinButtonOrTutorial tasks reloadForest sessions' (click backend')
James Laver's avatar
James Laver committed
83 84 85 86 87 88 89 90 91
        , H.div { className: "home-public container1" }
          [ renderPublic { }
          , H.div { className:"col-12 d-flex justify-content-center" }
            [ H.h1 {} [ H.text "" ]] -- H.span {className: "fa fa-star-o"} []
          , H.div { className: "home-landing-data container1" }
            [ blocksRandomText' landingData ]
          , license
          ]
        ] where
92 93
        click mBackend _ =
          case mBackend of
94 95 96 97 98 99 100 101
            Nothing -> do
              mLoc <- Config.matchCurrentLocation
              case mLoc of
                Nothing -> pure unit
                Just b -> do
                  T.write_ (Just b) backend
                  T.write_ true showLogin
            Just b -> T.write_ true showLogin
James Laver's avatar
James Laver committed
102

103 104
joinButtonOrTutorial :: forall e. T.Box GAT.Storage -> T2.ReloadS -> Sessions -> (e -> Effect Unit) -> R.Element
joinButtonOrTutorial tasks reloadForest sessions click =
James Laver's avatar
James Laver committed
105 106
  if Sessions.null sessions
  then joinButton click
107
  else tutorial {tasks, reloadForest, sessions: Sessions.unSessions sessions}
James Laver's avatar
James Laver committed
108 109 110
     
joinButton :: forall e. (e -> Effect Unit) -> R.Element
joinButton click =
111 112
  -- TODO Add G.C.L.F.form -- which backend to use?
  -- form { backend, sessions, visible }
113 114
  H.div { className: divClass
        , style: { paddingTop: "100px", paddingBottom: "100px" } }
115
        [ H.button { className: buttonClass, title, on: { click } } [ H.text "Log in" ] ] where
James Laver's avatar
James Laver committed
116 117
    title = "Connect to the server"
    divClass = "flex-space-around d-flex justify-content-center" 
118
    buttonClass = "btn btn-primary btn-lg btn-block"
James Laver's avatar
James Laver committed
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138

incompatible :: String
incompatible =
  "Sorry your browser is not compatible: use Firefox or Chromium instead."

video :: String -> R.Element
video fileDuration =
  H.div { className:"col-12 d-flex justify-content-center" }
  [ H.video
    { src, title, id, width: "900", type: "video/ogg", controls: true, muted: true }
    [ H.text incompatible ] ] where
      src = "http://dl.gargantext.org/" <> fileDuration
      title = "tutorial video here"
      id = "source_" <> fileDuration

data Tuto = Tuto { title :: String, id :: String, text  :: String }

summary :: R.Element
summary =
  H.div {}
139
  [ H.h3 {} [ H.text "Summary"]
James Laver's avatar
James Laver committed
140
  , H.ol {}
141
    [ sum "Getting Started for beginners" startTutos "alert-info"
James Laver's avatar
James Laver committed
142 143 144 145 146 147 148 149 150 151 152
    -- , sum "How to play (advanced users)?" playTutos "alert-warning"
    -- , sum "How to master (expert users)?" expertTutos "alert-danger"
    ]]
  where
    sum name tutos class' =
      H.div { className: "alert " <> class' }
      [ H.li {}
        [ H.h4 {} [ H.text name ]
        , H.ol {} (map toSummary tutos) ] ]          
    toSummary (Tuto x) = H.li {} [ H.a {href: "#" <> x.id} [ H.text x.title ]]

153
tutorial :: R2.Leaf (sessions :: Array Session, tasks :: T.Box GAT.Storage, reloadForest :: T.Box T2.Reload)
154
tutorial props = R.createElement tutorialCpt props []
155
tutorialCpt :: R.Component (sessions :: Array Session, tasks :: T.Box GAT.Storage, reloadForest :: T.Box T2.Reload)
156
tutorialCpt = here.component "tutorial" cpt where
157
  cpt {sessions, tasks, reloadForest} _ = do
158
    let folders = makeFolders sessions
159 160

    pure $ H.div { className: "mx-auto container" }
161
      [ H.div {className: "d-flex justify-content-center"} [ H.div { className: "folders" } folders ]
162 163
      -- , H.h1 {} [H.text "Tutorials"]
      -- , summary
164 165
      -- , H.h3 {} [H.text "Resources"]
      -- , section "How to start?" "alert-info" startTutos
166 167 168 169 170 171 172 173 174
      -- , section "How to play?" "alert-warning" playTutos
      -- , section "How to master?" "alert-danger" expertTutos
      ]
    where
      section name class' tutos =
        H.div {} $ Array.cons (H.h4 {} [ H.text name ]) (map (makeTuto class') tutos)
      makeTuto class' (Tuto x) =
        H.div { className : "alert " <> class', id: x.id}
        [ video x.id, H.h4 {} [ H.text x.title ], H.p  {} [ H.text x.text ] ]
James Laver's avatar
James Laver committed
175

176 177
      makeFolders :: Array Session -> Array R.Element
      makeFolders s = sessionToFolder <$> s where
Karen Konou's avatar
Karen Konou committed
178
        sessionToFolder session@(Session {treeId, username, backend: (Backend {name})}) = 
179
          H.span { className: "folder" } [
Karen Konou's avatar
Karen Konou committed
180
            H.div { className: "d-flex justify-content-center" } [ H.text (username <> "@" <> name) ]
181
          , H.div {} [ FV.folderView {session, tasks, reloadForest, nodeId: treeId, backFolder: false} ] ]
182

James Laver's avatar
James Laver committed
183 184
startTutos :: Array Tuto
startTutos =
185
  [ Tuto { title: "The tree to manage your data"
James Laver's avatar
James Laver committed
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
         , id: "0_tree.ogv"
         , text : "The tree enables you to control all your actions. The Tree has typed nodes. Each node has some attributes and some methods which depend on its type. This specific ergonomy helps the memorization of all the complexity of the GarganTexts' features: hence you do not need to remember all the documentation! Just remember these simple axioms, the Tree is built with parent-children relations of nodes which have specific attributes and methods. To get its methods and attributes, just click on the wheel near its name (for this feature, see advanced tutorial: how to play with GarganText)." }
  -- ,  Tuto { title : "Edit your profile"
  --         , id    : "0_edit.ogv"
  --         , text  : "At the root of the tree, there is your user node, parent of all others nodes. Your profile is what others users will see or search for to reach you or to watch/follow your work. If you delete it you remove all your data from the specified instance, clear and simple." }
  , Tuto { title : "Discover the nodes of the tree"
         , id    : "0_nodes.ogv"
         , text  : "Under your user node you have 3 main nodes: private, shared and public nodes. Each node has its specific attributes and methods! Under private node, all your work is private only. Under shared folder you can create teams to invite your partners, students or colleagues. Under public node, you can publish your work with the world: hello word!" }
  -- , Tuto { title : "Read a corpus"
  --        , id    : "video_tutorial.mp4#t=43,79"
  --        , text  : "Each fresh corpus node has 4 children only: docs, list, board, graph. The docs node enable you to manage your documents and rate it. The list node let the user to manage its ngrams. The board node sum up your analysis with the main charts you made with your ngrams. The graph node let you explore your data in a new way. Others new type of nodes are coming such as Phylo node..." }
  -- , Tuto { title : "Manage your ngrams"
  --        , id    : "video_tutorial.mp4#t=80,214"
  --        , text  : "By default, 4 types of ngrams are created: Terms extracted from text fields such as title or abstract, Institutes are extracted from the Institute field of the metadata, Sources, Authors. In that tutorial, you will learn how to change the status of ngrams, group it or create new categories. Remember you need to save your work with the sycn button. Then the charts are updated after each sync. Your work is either synchronous or asynchronous: you can save locally your data, disconnect your device and sync when your Internet connection is back." }
  -- , Tuto { title : "Watch with the board"
  --        , id    : "video_tutorial.mp4#t=215,237"
  --        , text  : "Build your own watchboard! Easy. All your list enable you to have charts to follow the evolution of your corpus." }
  -- , Tuto { title : "Explore with the graph"
  --        , id    : "video_tutorial.mp4#t=238,293"
  --        , text  : "With the map terms you have selected already, the graph is built. 3 main panels can be hidden or shown to give you more visual space: tree, controls, side panel. The side panel shows the legend, the selected data and the community you are watching. You can link your corpus with a community (check nodes methods to do this)." }
  -- , Tuto { title : "Edit ngrams in your documents"
  --        , id    : "video_tutorial.mp4#t=294,312"
  --        , text  : "All selected ngrams can be updated in the document and they are autmatically updated in the lists." }
  ]
210

James Laver's avatar
James Laver committed
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
playTutos :: Array Tuto
playTutos = []
  -- [ Tuto { title : "Again the tree is your friend"
  --        , id    : "video_tutorial_1.mp4#t=,46"
  --        , text  : "At the right of each node, its wheel shows its attributes or enables the execution of its methods. Each type of node has different attributes and methods to help user in an ergonomic way." }
  -- , Tuto { title : "Build your analysis"
  --        , id    : "video_tutorial_1.mp4#t=47,146"
  --        , text  : "To build your analysis you need to create a corpus. Suppose you want to create it in your private folder in this tutorial. Use the wheel to execute any function on the corpus node in the tree. You can search the local database instance, the web or through apis connected to public databases. It becomes easy to add many documents to your dynamic corpus." }
  -- , Tuto { title : "Add documents with files and download your data"
  --        , id    : "video_tutorial_1.mp4#t=157,166"
  --        , text  : "You can add CSV files from Gargantext V3 legacy version: in your previous account, export your corpus and download it on your device. Then, upload it to v4 as CSV file." }
  -- , Tuto { title : "Move your corpus elsewhere in the tree"
  --        , id    : "video_tutorial_1.mp4#t=167,175"
  --        , text  : "Each node can be moved with this function. Move it in your team to share it. Remove it to unshare it. Some nodes can not be moved, it depends on the types methods." }
  -- , Tuto { title : "Rename your corpus"
  --        , id    : "video_tutorial_1.mp4#t=145,160"
  --        , text  : "Some nodes can be renamed, most of them. But you can not rename your User Node which is the root of the tree." }
  -- , Tuto { title : "Delete your corpus"
  --        , id    : "video_tutorial_1.mp4#t=179,182"
  --        , text  : "Each node can be deleted with its children." }
  -- ]    

expertTutos :: Array Tuto
expertTutos = []
  -- [ Tuto { title : "Share with a team and send invitations"
  --        , id    : "video_tutorial_2.mp4#t=,46"
  --        , text  : "[Link to update]" }
  -- , Tuto { title : "Multi instance connections"
  --        , id    : "video_tutorial_2.mp4#t=,46"
  --        , text  : "[Link to update]" }
  -- , Tuto { title : "Freeze a graph"
  --        , id    : "video_tutorial_2.mp4#t=,46"
  --        , text  : "[Link to update]" }
  -- , Tuto { title : "Publish"
  --        , id    : "video_tutorial_2.mp4#t=,46"
  --        , text  : "[Link to update]" }
  -- , Tuto { title : "Link a set of document (corpus) with a set of persons (community)"
  --        , id    : "video_tutorial_2.mp4#t=,46"
  --        , text  : "[Link to update]" }
  -- ,  Tuto { title : "Social lists: cumulative work made easy"
  --         , id    : "video_tutorial_2.mp4#t=,46"
  --         , text  : "[Link to update]" }
  -- ,  Tuto { title : "Data mining with calc"
  --         , id    : "video_tutorial_2.mp4#t=,46"
  --         , text  : "[Link to update]" }
  -- ,  Tuto { title : "Collaborative sync edition notes"
  --         , id    : "video_tutorial_2.mp4#t=,46"
  --         , text  : "[Link to update]" }
  -- ,  Tuto { title : "Coding with our notebooks"
  --         , id    : "video_tutorial_2.mp4#t=,46"
  --         , text  : "[Link to update]" }
  -- ,  Tuto { title : "Our api"
  --         , id    : "video_tutorial_2.mp4#t=,46"
  --         , text  : "[Link to update]" }
  -- ,  Tuto { title : "A tour in the code"
  --         , id    : "video_tutorial_2.mp4#t=,46"
  --         , text  : "[Link to update]" }
  -- ]
269 270 271 272 273 274 275 276 277 278 279 280 281

blocksRandomText' :: LandingData -> R.Element
blocksRandomText' (LandingData hd) = blocksRandomText hd.blockTexts

blocksRandomText :: BlockTexts -> R.Element
blocksRandomText (BlockTexts bt) =
  H.div { className: "row" } ( map showBlock bt.blocks )
  where
    showBlock :: BlockText -> R.Element
    showBlock (BlockText b) =
      H.div { className: "col-md-4 content" }
      [ H.h3 {}
        [ H.a { href: b.href, title: b.title}
James Laver's avatar
James Laver committed
282 283
          [ H.i { className: b.icon } []
          , H.text ("   " <> b.titleText) ]]
284
        , H.p {} [ H.text b.text ]
James Laver's avatar
James Laver committed
285
        , H.p {} [ docButton b.docButton ]]
286 287 288

docButton :: Button -> R.Element
docButton (Button b) =
James Laver's avatar
James Laver committed
289 290 291 292
  H.a { className, href: b.href, target: "blank", title: b.title }
  [ H.span { aria: { hidden: true }, className: "fa fa-hand-right" } []
  , H.text b.text ] where
    className = "btn btn-outline-primary btn-sm spacing-class"
293

294 295
-- | TODO
-- <img src='logo.png' onmouseover="this.src='gargantextuel.png';" onmouseout="this.src='logo.png';" />
296 297
jumboTitle :: LandingData -> R.Element
jumboTitle (LandingData hd) =
James Laver's avatar
James Laver committed
298 299 300 301 302
  H.div {}
  [ H.div { className: "row" }
    [ H.div { className: "mx-auto" }
      [ H.div { id: "logo-designed" }
        [ H.img { src: "images/logo.png", title: hd.logoTitle } ]]]]
303

304
imageEnter :: forall t. LandingData -> t -> R.Element
305 306 307
imageEnter (LandingData hd) action =
  H.div {className: "row"}
  [ H.div {className: "col-md-offset-5 col-md-6 content"}
James Laver's avatar
James Laver committed
308 309 310
    [ H.img { src, action, id: "funnyimg", title: hd.imageTitle } ] ] where
      src = "images/Gargantextuel-212x300.jpg"