git.iko.soy/rowtype-yoga/psfp
on 982389d help sign in
100 lines 3.6 kB history raw
1module Container.Header where
3import Prelude
4import Data.Int (toNumber)
5import Data.Maybe (Maybe(..))
6import Data.Monoid (guard)
7import Data.Newtype (class Newtype)
8import Data.Nullable (Nullable, null)
9import Effect (Effect)
10import Effect.Class.Console (log)
11import JSS (jss, jssClasses)
12import React.Basic.DOM as R
13import React.Basic.Hooks (type (/\), Hook, ReactComponent, Ref, UseLayoutEffect, UseRef, UseState, coerceHook, component, element, readRefMaybe, useLayoutEffect, useRef, useState, (/\))
14import React.Basic.Hooks as React
15import Web.DOM (Node)
16import Web.Event.EventTarget (EventListener, eventListener)
17import Web.HTML (HTMLElement, window)
18import Web.HTML.HTMLElement (offsetTop)
19import Web.HTML.HTMLElement as HTMLElement
20import Web.HTML.Window (scrollY)
21import Yoga.SVG.Icon (trianglelogoIcon)
22import Yoga.Scroll.Listener as Scroll
23import Yoga.Theme.Styles (makeStylesJSS)
24import Yoga.Theme.Types (CSSTheme)
25import Yoga.Typography.Header (HeadingLevel(..), mkH)
27mkHeader ∷ Effect (ReactComponent {})
28mkHeader = do
29 h <- mkH
30 useStyles <-
31 makeStylesJSS
32 $ jssClasses \(theme ∷ CSSTheme) ->
33 { header:
34 jss
35 { backgroundColor: theme.interfaceColour
36 , borderBottom: "0"
37 , fontFamily: theme.headingFontFamily
38 , gridArea: "header"
39 , display: "flex"
40 , alignItems: "center"
41 , justifyContent: "flex-end"
42 , width: "100%"
43 , height: "80px"
44 , paddingTop: "10px"
45 , paddingBottom: "10px"
46 }
47 , sticky: jss { position: "fixed", top: "0", zIndex: 10 }
48 , title: jss { paddingRight: "30px" }
49 , logo:
50 jss
51 { width: "70px"
52 , height: "70px"
53 , padding: "5px"
54 , marginTop: "9px"
55 , marginRight: "7px"
56 , fill: theme.textColour
57 }
58 }
59 component "Header" \{} -> React.do
60 classes <- useStyles {}
61 shouldBeSticky /\ nodeRef <- useShouldBeSticky
62 pure
63 $ R.header
64 { ref: nodeRef
65 , className: classes.header <> " " <> guard shouldBeSticky classes.sticky
66 , children:
67 [ element h { level: H2, text: "Rowtype Yoga", className: Just classes.title }
68 , R.div { children: [ element trianglelogoIcon {} ], className: classes.logo }
69 ]
70 }
72newtype UseShouldBeSticky hooks
73 = UseShouldBeSticky (UseLayoutEffect Unit (UseState Boolean (UseRef (Nullable Node) hooks)))
75derive instance ntUseShouldBeSticky ∷ Newtype (UseShouldBeSticky hooks) _
76useShouldBeSticky ∷ Hook UseShouldBeSticky (Boolean /\ Ref (Nullable Node))
77useShouldBeSticky =
78 coerceHook React.do
79 nodeRef <- useRef null
80 mustBeSticky /\ modifyMustBeSticky <- useState false
81 let
82 setSticky = modifyMustBeSticky <<< const
83 useLayoutEffect unit do
84 maybeNode <- readRefMaybe nodeRef
85 case maybeNode >>= HTMLElement.fromNode of
86 Nothing -> do
87 log "Could not register listener because there was no node"
88 pure (pure unit)
89 Just element -> do
90 listener <- makeListener setSticky element
91 Scroll.registerListener listener
92 pure (mustBeSticky /\ nodeRef)
94makeListener ∷ (Boolean -> Effect Unit) -> HTMLElement -> Effect EventListener
95makeListener setSticky element = do
96 nodeStartPos <- offsetTop element
97 eventListener
98 $ const do
99 yPos <- window >>= scrollY <#> toNumber
100 setSticky $ nodeStartPos < yPos