git.iko.soy/rowtype-yoga/psfp
on 50f5e9d help sign in
262 lines 8.1 kB history raw
1module PSLayout where
3import Prelude
4import Data.Array as A
5import Data.Array as Array
6import Data.Array.NonEmpty as NEA
7import Data.Maybe (Maybe(..), fromMaybe)
8import Data.Nullable (Nullable)
9import Data.Nullable as Nullable
10import Data.String as String
11import Data.Tuple.Nested ((/\))
12import Debug.Trace (spy)
13import Effect (Effect)
14import JSS (jss, jssClasses)
15import Justifill (justifill)
16import Milkis.Impl (FetchImpl)
17import React.Basic (JSX, ReactComponent)
18import React.Basic.DOM (unsafeCreateDOMComponent)
19import React.Basic.DOM as R
20import React.Basic.Helpers (jsx)
21import React.Basic.Hooks (ReactChildren, component, componentWithChildren, element, reactChildrenToArray, useEffect, useState)
22import React.Basic.Hooks as React
23import Unsafe.Coerce (unsafeCoerce)
24import Yoga.Box.Component as Box
25import Yoga.CompileEditor.Component (mkCompileEditor)
26import Yoga.Compiler.Api (apiCompiler)
27import Yoga.FillInTheGaps.Component as FillInTheGaps
28import Yoga.FillInTheGaps.Logic (parseSegments)
29import Yoga.Header.Component (mkHeader)
30import Yoga.Helpers ((?||))
31import Yoga.InlineCode.Component as InlineCode
32import Yoga.Theme (fromTheme)
33import Yoga.Theme.CSSBaseline (mkCssBaseline)
34import Yoga.Theme.Default (darkTheme)
35import Yoga.Theme.Provider (mkThemeProvider)
36import Yoga.Theme.Styles (makeStylesJSS)
37import Yoga.Theme.Types (CSSTheme)
38import Yoga.Typography.Header (HeadingLevel(..), mkH)
39import Yoga.Typography.Paragraph (mkP)
40import Yoga.WithSidebar.Component (makeComponent) as WithSidebar
42type SiteQueryResult
43 = { site ∷
44 { siteMetadata ∷
45 { title ∷ String
46 , menuLinks ∷ Array { name ∷ String, link ∷ String }
47 }
48 }
49 }
51type PreProps
52 = { children ∷
53 Nullable
54 { props ∷
55 Nullable
56 { mdxType ∷ Nullable String
57 , children ∷ Nullable String
58 , className ∷ Nullable String
59 }
60 }
61 }
63mkLayout ∷
64 FetchImpl ->
65 Effect
66 ( ReactComponent
67 { children ∷ ReactChildren JSX
68 , siteInfo ∷ SiteQueryResult
69 }
70 )
71mkLayout fetchImpl = do
72 themeProvider <- mkThemeProvider
73 mdxProviderComponent <- mkMdxProviderComponent fetchImpl
74 componentWithChildren "MDXLayout" \{ children, siteInfo } -> React.do
75 pure
76 $ element themeProvider
77 { theme: fromTheme darkTheme
78 , children:
79 [ element mdxProviderComponent
80 { children
81 , siteInfo
82 }
83 ]
84 }
86mkSecret ∷ Effect (ReactComponent { kids ∷ Array JSX, visible ∷ Boolean, register ∷ Effect Unit })
87mkSecret = do
88 component "Secret" \{ kids, visible, register } -> React.do
89 useEffect visible do
90 unless visible register
91 pure mempty
92 pure
93 $ R.div
94 { style: R.css { visibility: if visible then "visible" else "hidden" }
95 , children: kids
96 }
98mkMdxProviderComponent ∷
99 FetchImpl ->
100 Effect
101 ( ReactComponent
102 { children ∷ ReactChildren JSX
103 , siteInfo ∷ SiteQueryResult
104 }
105 )
106mkMdxProviderComponent fetchImpl = do
107 cssBaseline <- mkCssBaseline
108 editor <- mkCompileEditor fetchImpl
109 fillInTheGaps <- FillInTheGaps.makeComponent
110 box <- Box.makeComponent
111 sidebar <- mkSidebar
112 header <- mkHeader
113 yogaInlineCode <- InlineCode.makeComponent
114 h <- mkH
115 p <- mkP
116 secret <- mkSecret
117 useStyles <-
118 makeStylesJSS
119 $ jssClasses \(theme ∷ CSSTheme) ->
120 { code:
121 { fontFamily: theme.codeFontFamily # NEA.head
122 , backgroundColor: theme.interfaceColour
123 , fontSize: "10pt"
124 , border: "1px solid #383c39"
125 , padding: "3px"
126 , borderRadius: "3px"
127 }
128 , flexer:
129 { display: "flex"
130 , flexDirection: "row"
131 }
132 }
133 componentWithChildren "MDXProviderComponent" \{ children, siteInfo } -> React.do
134 classes <- useStyles {}
135 visibleThroughKey /\ updateVisible <- useState ""
136 let
137 baseline child = element cssBaseline { kids: child }
139 kids = reactChildrenToArray children
141 visibleKids =
142 spy "visibleKids"
143 $ fromMaybe kids do
144 i <- kids # A.findIndex (\x -> (unsafeCoerce x).key == visibleThroughKey)
145 pure $ A.take (i + 1) kids
147 siteInfoJSX =
148 R.div
149 { children:
150 [ jsx header { className: "" } [ R.text siteInfo.site.siteMetadata.title ]
151 , element sidebar { links: siteInfo.site.siteMetadata.menuLinks }
152 , jsx box {} visibleKids
153 ]
154 }
156 mdxComponents =
157 { h1:
158 \props ->
159 element h ({ level: H2, text: props.children, className: Nothing })
160 , h2:
161 \props ->
162 element h { level: H3, text: props.children, className: Nothing }
163 , h3:
164 \props ->
165 element h { level: H4, text: props.children, className: Nothing }
166 , p:
167 \props ->
168 R.div
169 { children: [ element p { text: props.children } ]
170 }
171 -- , thematicBreak:
172 -- \props -> jsx secret { register: updateSections (Map.insert ) }
173 , inlineCode:
174 \props -> do
175 R.span { className: classes.code, children: props.children }
176 , pre:
177 \(props ∷ PreProps) -> do
178 let
179 childrenQ = Nullable.toMaybe props.children
181 propsQ = (_.props >>> Nullable.toMaybe) =<< childrenQ
183 mdxTypeQ = (_.mdxType >>> Nullable.toMaybe) =<< propsQ
185 childrenQ2 = (_.children >>> Nullable.toMaybe) =<< propsQ
187 classNameQ = (_.className >>> Nullable.toMaybe) =<< propsQ
189 isCode = fromMaybe false (mdxTypeQ <#> eq "code")
191 codeQ = childrenQ2
193 height =
194 (fromMaybe 200 >>> show >>> (_ <> "px")) do
195 code <- codeQ
196 pure
197 ( String.split (String.Pattern "\n") code
198 # Array.length
199 # \x -> (x * 12) + 100
200 )
202 language = fromMaybe "" (classNameQ >>= String.stripPrefix (String.Pattern "language-"))
203 case isCode, language of
204 true, "puregaps" ->
205 element fillInTheGaps
206 { initialSegments: parseSegments (codeQ ?|| "")
207 , update: \segs -> pure unit
208 }
209 true, _ ->
210 element editor
211 { initialCode: fromMaybe "" codeQ
212 , height
213 , language
214 }
215 false, _ -> element (unsafeCreateDOMComponent "pre") props
216 }
217 useEffect (A.length kids) do
218 let
219 firstGaps = kids # A.find (\x -> (unsafeCoerce x).props.mdxType == "pre" && ((unsafeCoerce x).props.children.props.className == "language-puregaps")) <#> (\x -> (unsafeCoerce x).key)
221 lastKey = kids # A.last # unsafeCoerce # _.key
222 updateVisible (const (firstGaps ?|| lastKey))
223 pure mempty
224 pure
225 $ baseline
226 [ element mdxProvider
227 { children:
228 [ siteInfoJSX
229 ]
230 , components: mdxComponents
231 }
232 ]
234mkSidebar = do
235 withSidebar <- WithSidebar.makeComponent
236 useStyles <-
237 makeStylesJSS
238 $ jssClasses \(theme ∷ CSSTheme) ->
239 { flexer:
240 jss
241 { display: "flex"
242 , flexDirection: "row"
243 , width: "300px"
244 , height: "300px"
245 }
246 }
247 component "Sidebar" \{ links } -> React.do
248 classes <- useStyles {}
249 pure
250 $ element withSidebar
251 ( justifill
252 { sidebarChildren: [ R.div_ [ R.text "hahahaha" ] ]
253 , notSidebarChildren: [] ∷ Array JSX
254 }
255 )
257foreign import mdxProvider ∷
258 ∀ r.
259 ReactComponent
260 { components ∷ { | r } -- TODO Don't lie
261 , children ∷ Array JSX
262 }