Home.purs 18 KB
Newer Older
arturo's avatar
arturo committed
1
module Gargantext.Components.Nodes.Home
2
  ( HomeAction(..)
arturo's avatar
arturo committed
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
  , HomeProps
  , State(..)
  , Tuto(..)
  , TutorialProps
  , blocksRandomText
  , blocksRandomText'
  , docButton
  , expertTutos
  , here
  , homeLayout
  , homeLayoutCpt
  , imageEnter
  , incompatible
  , initialState
  , joinButtonOrTutorial
  , jumboTitle
  , langLandingData
  , license
21
  , performHomeAction
arturo's avatar
arturo committed
22 23 24 25 26 27 28 29
  , playTutos
  , startTutos
  , summary
  , tutorial
  , tutorialCpt
  , video
  )
  where
30

31 32
import Gargantext.Prelude

33
import Data.Foldable (intercalate)
34
import Data.Maybe (Maybe(..))
35
import Data.Newtype (class Newtype)
36
import Effect (Effect)
arturo's avatar
arturo committed
37
import Gargantext.Components.App.Store (Boxes)
arturo's avatar
arturo committed
38
import Gargantext.Components.Bootstrap as B
39
import Gargantext.Components.Bootstrap.Types (ComponentStatus(..), Elevation(..), ModalSizing(..), Position(..), TooltipPosition(..), Variant(..))
40
import Gargantext.Components.Data.Landing (BlockText(..), BlockTexts(..), Button(..), LandingData(..))
41
import Gargantext.Components.FolderView as FV
42 43 44
import Gargantext.Components.Lang (LandingLang(..))
import Gargantext.Components.Lang.Landing.EnUS as En
import Gargantext.Components.Lang.Landing.FrFR as Fr
45
import Gargantext.Config as Config
46
import Gargantext.Sessions (Session(..), Sessions, Action(Logout), unSessions)
Alexandre Delanoë's avatar
Alexandre Delanoë committed
47
import Gargantext.Sessions as Sessions
48
import Gargantext.Sessions.Types (Session(..), cleanBackendUrl)
49
import Gargantext.Utils.Reactix as R2
50 51 52 53
import Reactix as R
import Reactix.DOM.HTML as H
import Routing.Hash (setHash)
import Toestand as T
54

55 56 57
import Effect.Console (log)


James Laver's avatar
James Laver committed
58 59
here :: R2.Here
here = R2.here "Gargantext.Components.Nodes.Home"
60

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

63
derive instance Newtype State _
64 65

initialState :: State
James Laver's avatar
James Laver committed
66
initialState = State { userName: "", password: "" }
67

68
data HomeAction
69 70 71 72 73
  = Documentation
  | Enter
  | Login
  | SignUp

74 75 76 77 78
performHomeAction :: HomeAction -> Effect Unit
performHomeAction Documentation = pure unit
performHomeAction Enter = void $ setHash "/search"
performHomeAction Login = void $ setHash "/login"
performHomeAction SignUp = pure unit
79

80 81 82
langLandingData :: LandingLang -> LandingData
langLandingData LL_FR = Fr.landingData
langLandingData LL_EN = En.landingData
83 84 85

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

86
type HomeProps =
87
  ( boxes     :: Boxes )
88

89
homeLayout :: R2.Leaf HomeProps
90
homeLayout = R2.leaf homeLayoutCpt
91
homeLayoutCpt :: R.Component HomeProps
James Laver's avatar
James Laver committed
92
homeLayoutCpt = here.component "homeLayout" cpt
93
  where
94
    cpt { boxes: boxes@{ backend
95
                       , lang
96 97
                       , sessions
                       , showLogin }
98
        } _ = do
arturo's avatar
arturo committed
99 100
      -- | States
      -- |
101
      backend'  <- T.useLive T.unequal backend
James Laver's avatar
James Laver committed
102
      sessions' <- T.useLive T.unequal sessions
103
      lang'     <- T.useLive T.unequal lang
arturo's avatar
arturo committed
104 105 106

      -- | Computed
      -- |
107
      let landingData = langLandingData lang'
arturo's avatar
arturo committed
108 109 110 111

      -- | Behaviors
      -- |
      let
112 113
        click mBackend _ =
          case mBackend of
114 115 116 117 118 119 120
            Nothing -> do
              mLoc <- Config.matchCurrentLocation
              case mLoc of
                Nothing -> pure unit
                Just b -> do
                  T.write_ (Just b) backend
                  T.write_ true showLogin
Alexandre Delanoë's avatar
Alexandre Delanoë committed
121
            Just _ -> T.write_ true showLogin
James Laver's avatar
James Laver committed
122

arturo's avatar
arturo committed
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
      -- | Render
      -- |
      pure $

        R.fragment
        [
          H.div { className: "home-title" }
          [
            H.div
            { className: "home-title__logo" }
            [
              jumboTitle landingData
            ]
          ,
            H.div
            { className: "home-title__jumbo" }
            [
              joinButtonOrTutorial boxes sessions' (click backend')
            ]
          ]
          -- @TODO
          -- H.div { className: "home-research-form" } []
        ,
          blocksRandomText' landingData
        ,
          B.wad
          [ "mt-8" ]
          [
            license
          ]
        ]


156
joinButtonOrTutorial :: forall e. Boxes
157 158 159
                     -> Sessions
                     -> (e -> Effect Unit)
                     -> R.Element
160
joinButtonOrTutorial boxes sessions click =
James Laver's avatar
James Laver committed
161 162
  if Sessions.null sessions
  then joinButton click
163
  else tutorial { boxes, sessions: Sessions.unSessions sessions }
164

James Laver's avatar
James Laver committed
165 166
joinButton :: forall e. (e -> Effect Unit) -> R.Element
joinButton click =
167 168
  -- TODO Add G.C.L.F.form -- which backend to use?
  -- form { backend, sessions, visible }
arturo's avatar
arturo committed
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
  B.wad
  [ "d-flex", "flex-space-around", "justify-content-center", "align-items-center", "h-100" ]
  [
    H.button
    { className: "btn btn-primary py-2 w-1/3 font-size-140"
    , title: "Connect to the server"
    , on: { click }
    , style: { minWidth: "200px"}
    }
    [
      B.icon
      { name: "sign-in"
      , className: "font-size-90"
      }
    ,
      B.wad_
      [ "virtual-space", "w-2", "d-inline-block" ]

    ,
      H.text "Log in"
    ]
  ]
James Laver's avatar
James Laver committed
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210

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 {}
211
  [ H.h3 {} [ H.text "Summary"]
James Laver's avatar
James Laver committed
212
  , H.ol {}
213
    [ sum "Getting Started for beginners" startTutos "alert-info"
James Laver's avatar
James Laver committed
214 215 216 217 218 219 220 221
    -- , 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 ]
222
        , H.ol {} (map toSummary tutos) ] ]
James Laver's avatar
James Laver committed
223 224
    toSummary (Tuto x) = H.li {} [ H.a {href: "#" <> x.id} [ H.text x.title ]]

225
type TutorialProps =
226 227
  ( boxes :: Boxes
  , sessions :: Array Session )
228 229

tutorial :: R2.Leaf TutorialProps
230
tutorial = R2.leaf tutorialCpt
231
tutorialCpt :: R.Component TutorialProps
232
tutorialCpt = here.component "tutorial" cpt where
Karen Konou's avatar
Karen Konou committed
233
  cpt { boxes, sessions } _ = do
arturo's avatar
arturo committed
234 235 236 237 238 239

    pure $

      H.div
      { className: "home-tutorial" } $
      makeFolders sessions
240

241 242
      -- , H.h1 {} [H.text "Tutorials"]
      -- , summary
243 244
      -- , H.h3 {} [H.text "Resources"]
      -- , section "How to start?" "alert-info" startTutos
245 246 247
      -- , section "How to play?" "alert-warning" playTutos
      -- , section "How to master?" "alert-danger" expertTutos
    where
Alexandre Delanoë's avatar
Alexandre Delanoë committed
248
      {-
249 250 251 252 253
      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 ] ]
Alexandre Delanoë's avatar
Alexandre Delanoë committed
254
      -}
James Laver's avatar
James Laver committed
255

Karen Konou's avatar
Karen Konou committed
256
      onSignOutClick session = void $ Sessions.change (Logout session) boxes.sessions
257 258


259
      makeFolders :: Array Session -> Array R.Element
260 261
      makeFolders s = sessionToFolder <$> s
        where
262
          sessionToFolder session@(Session {treeId, username, backend}) =
arturo's avatar
arturo committed
263 264 265 266 267 268 269 270 271 272 273 274 275
            H.div
            { className: intercalate " "
                [ "home-title__folders"
                , "card border-dark"
                ]
            }
            [
              H.div
              { className: "card-header bg-dark color-white" }
              [
                B.wad
                [ "d-flex", "align-items-center" ]
                [
276 277 278 279 280 281 282 283 284
                  B.wad
                  [ "text-left", "w-10/12" ]
                  [
                    B.icon
                    { name: "user", className: "pr-1" }
                  ,
                    B.span_ $
                    username <> "@" <> cleanBackendUrl backend
                  ]
arturo's avatar
arturo committed
285
                ,
286 287 288 289 290 291 292 293 294 295 296
                  B.wad
                  [ "text-right", "w-2/12" ]
                  [
                    B.tooltipContainer
                    { position: TooltipPosition Top
                    , delayShow: 600
                    , tooltipSlot:
                        B.span_ "Log out"
                    , defaultSlot:
                        B.iconButton
                        { name: "sign-out"
Karen Konou's avatar
Karen Konou committed
297
                        , callback: \_ -> onSignOutClick session
298 299 300 301 302
                        , elevation: Level2
                        , className: "text-light"
                        }
                    }
                  ]
arturo's avatar
arturo committed
303 304 305 306 307 308 309 310 311 312 313 314
                ]
              ]
            ,
              H.div
              { className: "card-body" }
              [
                FV.folderView
                { nodeId: treeId
                , session
                }
              ]
            ]
315
      
316

James Laver's avatar
James Laver committed
317 318
startTutos :: Array Tuto
startTutos =
319
  [ Tuto { title: "The tree to manage your data"
James Laver's avatar
James Laver committed
320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343
         , 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." }
  ]
344

James Laver's avatar
James Laver committed
345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364
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." }
365
  -- ]
James Laver's avatar
James Laver committed
366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402

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]" }
  -- ]
403 404 405 406 407 408

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

blocksRandomText :: BlockTexts -> R.Element
blocksRandomText (BlockTexts bt) =
arturo's avatar
arturo committed
409 410 411
  B.wad
  [ "d-flex", "gap-3" ]
  ( map showBlock bt.blocks )
412 413 414
  where
    showBlock :: BlockText -> R.Element
    showBlock (BlockText b) =
arturo's avatar
arturo committed
415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435
      B.wad
      [ "w-1/3" ]
      [
        H.h3
        {}
        [
          H.a
          { href: b.href
          , title: b.title
          }
          [
            H.i { className: b.icon } []
          , H.text ("   " <> b.titleText) ]
        ]
      ,
        B.wad
        [ "my-2" ]
        [ H.text b.text ]
      ,
        H.p {} [ docButton b.docButton ]
      ]
436 437 438

docButton :: Button -> R.Element
docButton (Button b) =
arturo's avatar
arturo committed
439 440 441 442 443 444 445 446 447 448 449 450 451 452
  H.a
  { className: "btn btn-outline-secondary btn-sm spacing-class"
  , href: b.href
  , target: "blank"
  , title: b.title
  }
  [
    H.span
    { aria: { hidden: true }
    , className: "fa fa-hand-right"
    } []
  ,
    H.text b.text
  ]
453

454 455
-- | TODO
-- <img src='logo.png' onmouseover="this.src='gargantextuel.png';" onmouseout="this.src='logo.png';" />
456 457
jumboTitle :: LandingData -> R.Element
jumboTitle (LandingData hd) =
arturo's avatar
arturo committed
458 459 460 461
  H.img
  { src: "images/logo.png"
  , title: hd.logoTitle
  }
462

463
imageEnter :: forall t. LandingData -> t -> R.Element
464 465 466
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
467 468
    [ H.img { src, action, id: "funnyimg", title: hd.imageTitle } ] ] where
      src = "images/Gargantextuel-212x300.jpg"
arturo's avatar
arturo committed
469 470 471 472 473 474 475 476 477 478 479

license :: R.Element
license =
  H.div
  { className: "home-license" }
  [
    H.text "GarganText "
  ,
    B.icon
    { name: "registered" }
  ,
480
    H.text " is made by the "
arturo's avatar
arturo committed
481 482 483 484 485 486
  ,
    H.a
    { href: "https://iscpif.fr"
    , target: "_blank"
    }
    [
Alexandre Delanoë's avatar
Alexandre Delanoë committed
487
      H.text "French Research Agency (FRA), Complex Systems Institute of Paris-Île de France"
arturo's avatar
arturo committed
488 489 490 491 492 493 494 495
    ]
  ,
    H.a
    { href: "http://gitlab.iscpif.fr/humanities/gargantext/blob/stable/LICENSE"
    , target: "_blank"
    , title: "Legal instructions of the project."
    }
    [
496
      H.text ", with aGPLV3 and CECILL variant Affero compliant licences, "
arturo's avatar
arturo committed
497 498 499
    ]
  ,
    B.icon
500
    { name: "copyrights" }
arturo's avatar
arturo committed
501 502 503 504 505 506
  ,
    H.a
    { href: "https://cnrs.fr"
    , target: "_blank"
    }
    [
507
      H.text "CNRS-ISCPIF/UAR-3611_2017-Present"
arturo's avatar
arturo committed
508 509 510 511
    ]
  ,
    H.text "."
  ]