git.iko.soy/rowtype-yoga/psfp
on 21e940e help sign in
102 lines 3.4 kB history raw
1module Container.Header where
3import Prelude
5import Control.Alt ((<|>))
6import Data.Int (toNumber)
7import Data.Maybe (Maybe(..), fromMaybe)
8import Data.Monoid (guard)
9import Data.Nullable (null)
10import Debug.Trace (spy)
11import Effect (Effect)
12import React.Basic.DOM (css)
13import React.Basic.DOM as R
14import React.Basic.Hooks (ReactComponent, component, element, readRef, readRefMaybe, useEffect, useLayoutEffect, useRef, useState, writeRef, (/\))
15import React.Basic.Hooks as React
16import SVG.Icon (pslogoIcon)
17import Theme.Styles (makeStyles)
18import Theme.Types (CSSTheme)
19import Typography.Header (HeadingLevel(..), mkH)
20import Web.Event.Event (EventType(..))
21import Web.Event.EventTarget (addEventListener, eventListener, removeEventListener)
22import Web.HTML (window)
23import Web.HTML.HTMLElement (offsetTop)
24import Web.HTML.HTMLElement as HTMLElement
25import Web.HTML.Window (scrollY, toEventTarget)
27mkHeader ∷ Effect (ReactComponent {})
28mkHeader = do
29 h <- mkH
30 useStyles <-
31 makeStyles \(theme ∷ CSSTheme) ->
32 { header:
33 css
34 { backgroundColor: theme.backgroundColour
35 , borderBottom: "1px solid " <> theme.highlightColour
36 , paddingLeft: "20px"
37 , fontFamily: theme.textFontFamily
38 , gridArea: "header"
39 , display: "flex"
40 , alignItems: "center"
41 , width: "100vw"
42 , height: "80px"
43 }
44 , sticky: css { position: "fixed", top: "0" }
45 , logo:
46 css
47 { width: "70px"
48 , height: "70px"
49 , padding: "5px"
50 , marginRight: "7px"
51 , fill: theme.textColour
52 }
53 }
54 useScrollYPosition <- mkUseScrollYPosition
55 component "Header" \{} -> React.do
56 classes <- useStyles
57 mustBeSticky /\ modifyMustBeSticky <- useState false
58 nodeY /\ modifyNodeY <- useState 0
59 nodeOffset /\ modifyONP <- useState Nothing
60 nodeRef <- useRef null
61 scrollYPos <- useScrollYPosition
62 useEffect scrollYPos do
63 maybeNode <- readRefMaybe nodeRef
64 let maybeElem = maybeNode >>= HTMLElement.fromNode
65 case maybeElem of
66 Nothing -> pure (pure unit)
67 Just element -> do
68 offset <- offsetTop element
69 modifyONP case _ of
70 Just x -> Just x
71 Nothing -> Just offset
72 let offset' = fromMaybe offset nodeOffset
73 modifyMustBeSticky
74 if toNumber scrollYPos > offset'
75 then const true
76 else const false
77 pure (pure unit)
79 pure
80 $ R.header
81 { ref: nodeRef
82 , className: classes.header <> " " <> guard mustBeSticky classes.sticky
83 , children:
84 [ R.div { children: [ element pslogoIcon {} ], className: classes.logo }
85 , element h { level: H2, text: "Purescript", className: Nothing }
86 ]
87 }
89mkUseScrollYPosition = do
90 initialPosition <- window >>= scrollY
91 pure $ React.do
92 scrollPosY /\ modifyScrollPosY <- useState initialPosition
93 useLayoutEffect unit do
94 target <- window <#> toEventTarget
95 let eventType = EventType "scroll"
96 listener <- eventListener
97 \_ -> window >>= scrollY >>= \newPos -> modifyScrollPosY (const newPos)
98 addEventListener eventType listener false target
99 let _ = spy "registered event listener" unit
100 pure $
101 removeEventListener eventType listener false target
102 pure $ scrollPosY