git.iko.soy/rowtype-yoga/psfp
on master help sign in
Rerenders too much
commit6c57a5570c0a885a3e59a62638324c42139e36c6 authorMark Eibes <mark.eibes@gmail.com> dateWed 15 Apr 2020, 22:52 (6 years ago) parent5dfb687
4 files changed+63−26
blog/.psc-ide-port+1−1 blog/src/components/PSLayout.purs+36−13 components/src/Yoga/FillInTheGaps/Component.purs+25−11 components/src/Yoga/FillInTheGaps/Stories.purs+1−1
blog/.psc-ide-port+1−1
@@ -1 +1 @@
1−15613
1+15549
blog/src/components/PSLayout.purs+36−13
@@ -1,17 +1,20 @@
11module PSLayout where
22
33import Prelude
4+
5+import Data.Array (foldMap)
46import Data.Array as A
57import Data.Array as Array
68import Data.Array.NonEmpty as NEA
7−import Data.Function.Uncurried (mkFn2)
9+import Data.Either (Either(..))
810import Data.Maybe (Maybe(..), fromMaybe, isJust)
9−import Data.Nullable (Nullable, toMaybe)
11+import Data.Nullable (Nullable)
1012import Data.Nullable as Nullable
1113import Data.String as String
1214import Data.Tuple.Nested ((/\))
13−import Debug.Trace (spy)
1415import Effect (Effect)
16+import Effect.Aff (launchAff_)
17+import Effect.Class (liftEffect)
1518import JSS (jss, jssClasses)
1619import Justifill (justifill)
1720import Milkis.Impl (FetchImpl)
@@ -23,14 +26,16 @@ import React.Basic.Hooks (ReactChildren, component, componentWithChildren, eleme
2326import React.Basic.Hooks as React
2427import Unsafe.Coerce (unsafeCoerce)
2528import Yoga.Box.Component as Box
29+import Yoga.ClickAway.Component as ClickAway
2630import Yoga.CompileEditor.Component (mkCompileEditor)
2731import Yoga.Compiler.Api (apiCompiler)
2832import Yoga.Compiler.Types (Compiler)
2933import Yoga.FillInTheGaps.Component as FillInTheGaps
30−import Yoga.FillInTheGaps.Logic (complete, parseSegments)
34+import Yoga.FillInTheGaps.Logic (findResult, parseSegments, toCode)
3135import Yoga.Header.Component (mkHeader)
3236import Yoga.Helpers ((?||))
3337import Yoga.InlineCode.Component as InlineCode
38+import Yoga.Modal.Component as Modal
3439import Yoga.Theme (fromTheme)
3540import Yoga.Theme.CSSBaseline (mkCssBaseline)
3641import Yoga.Theme.Default (darkTheme)
@@ -97,6 +102,13 @@ mkSecret = do
97102 , children: kids
98103 }
99104
105+isQuiz ∷ JSX -> Boolean
106+isQuiz a =
107+ (unsafeCoerce a).props.mdxType == "pre"
108+ && ((unsafeCoerce a).props.children.props.className == "language-purescript")
109+ && ((unsafeCoerce a).props.children.props.mdxType == "code")
110+ && ((unsafeCoerce a).props.children.props.children # parseSegments # isJust)
111+
100112mkMdxProviderComponent ∷
101113 ∀ r.
102114 { | Compiler r } ->
@@ -114,6 +126,8 @@ mkMdxProviderComponent compiler = do
114126 sidebar <- mkSidebar
115127 header <- mkHeader
116128 yogaInlineCode <- InlineCode.makeComponent
129+ modal <- Modal.makeComponent
130+ clickAway <- ClickAway.makeComponent
117131 h <- mkH
118132 p <- mkP
119133 secret <- mkSecret
@@ -136,6 +150,8 @@ mkMdxProviderComponent compiler = do
136150 componentWithChildren "MDXProviderComponent" \{ children, siteInfo } -> React.do
137151 classes <- useStyles {}
138152 visibleThrough /\ updateVisible <- useState 1
153+ questions /\ updateQuestions <- useState []
154+ maybeModal /\ updateModal <- useState Nothing
139155 let
140156 baseline child = element cssBaseline { kids: child }
141157
@@ -146,10 +162,7 @@ mkMdxProviderComponent compiler = do
146162 if i >= visibleThrough then
147163 { i, acc }
148164 else
149− if (unsafeCoerce a).props.mdxType == "pre"
150− && ((unsafeCoerce a).props.children.props.className == "language-purescript")
151− && ((unsafeCoerce a).props.children.props.mdxType == "code")
152− && ((unsafeCoerce a).props.children.props.children # parseSegments # isJust) then
165+ if isQuiz a then
153166 { i: i + 1, acc: A.snoc acc a }
154167 else
155168 { i, acc: A.snoc acc a }
@@ -218,11 +231,14 @@ mkMdxProviderComponent compiler = do
218231 jsx box {}
219232 [ element fillInTheGaps
220233 { initialSegments
221− , update:
222− \segs ->
223− when (complete segs)
224− $ updateVisible
225− (_ + 1)
234+ , incantate: \segments -> launchAff_ do
235+ let code = toCode segments
236+ result <- compiler.compileAndRun { code }
237+ liftEffect case result of
238+ Right r | String.stripSuffix (String.Pattern "\n") r.stdout == (findResult $ join segments) ->
239+ updateVisible (_ + 1)
240+ _ ->
241+ updateModal (const $ Just { title: "Failed", kids: [R.text "Try again"] })
226242 }
227243 ]
228244 true, _, _ ->
@@ -241,6 +257,13 @@ mkMdxProviderComponent compiler = do
241257 ]
242258 , components: mdxComponents
243259 }
260+ , maybeModal # foldMap
261+ (\modalProps ->
262+ fragment [
263+ element clickAway { allowEscape: Just true, onClick: updateModal (const Nothing), style: Nothing },
264+ element modal (justifill modalProps)
265+ ]
266+ )
244267 ]
245268
246269mkSidebar = do
components/src/Yoga/FillInTheGaps/Component.purs+25−11
@@ -4,18 +4,20 @@ import Prelude
44import Data.Array as A
55import Data.Tuple.Nested ((/\))
66import Effect (Effect)
7−import Effect.Aff (Milliseconds(..), delay)
8−import Effect.Class (liftEffect)
97import Justifill (justifill)
108import React.Basic (JSX, ReactComponent, element)
119import React.Basic.DOM as R
12−import React.Basic.Hooks (component, useState)
10+import React.Basic.Events (handler_)
11+import React.Basic.Helpers (jsx)
12+import React.Basic.Hooks (component, useEffect, useState)
1313import React.Basic.Hooks as React
14−import React.Basic.Hooks.Aff (useAff)
1514import React.Basic.SyntaxHighlighter.Component (HighlighterTheme, syntaxHighlighterImpl)
16−import Yoga.FillInTheGaps.Logic (Segment(..), updateSegments)
15+import Yoga.Button.Component (ButtonType(..), mkButton)
16+import Yoga.FillInTheGaps.Logic (Segment(..), complete, updateSegments)
1717import Yoga.Helpers ((?||))
1818import Yoga.InlineCode.Component as InlineCode
19+import Yoga.Stack.Component as Stack
20+import Yoga.Cluster.Component as Cluster
1921import Yoga.Theme.Styles (useTheme)
2022import Yoga.Theme.Syntax (mkHighlighterTheme)
2123
@@ -43,13 +45,25 @@ renderSegments highlighterTheme ic update arrs = R.div_ (A.mapWithIndex renderLi
4345 else
4446 mempty
4547
46−makeComponent ∷ Effect (ReactComponent { initialSegments ∷ Array (Array Segment), update ∷ Array (Array Segment) -> Effect Unit })
48+makeComponent ∷ Effect (ReactComponent { initialSegments ∷ Array (Array Segment), incantate ∷ Array (Array Segment) -> Effect Unit })
4749makeComponent = do
4850 ic <- InlineCode.makeComponent
49− component "FillInTheGaps" \{ initialSegments, update } -> React.do
51+ btn <- mkButton
52+ stack <- Stack.makeComponent
53+ cluster <- Cluster.makeComponent
54+ component "FillInTheGaps" \{ initialSegments, incantate } -> React.do
5055 segments /\ modifySegments <- useState initialSegments
51− useAff segments do
52− delay (200.0 # Milliseconds)
53− update segments # liftEffect
5456 highlighterTheme <- useTheme <#> mkHighlighterTheme
55− pure $ renderSegments highlighterTheme ic (modifySegments) segments
57+ pure
58+ $ jsx stack {}
59+ [ renderSegments highlighterTheme ic (modifySegments) segments
60+ , jsx cluster {}
61+ [ R.div_
62+ [ jsx btn
63+ { onClick: handler_ (incantate segments)
64+ , buttonType: if complete segments then HighlightedButton else DisabledButton
65+ }
66+ [ R.text "Incantate" ]
67+ ]
68+ ]
69+ ]
components/src/Yoga/FillInTheGaps/Stories.purs+1−1
@@ -14,7 +14,7 @@ stories = do
1414 storiesOf "FillInTheGaps" do
1515 addDecorator fullScreenDecorator
1616 add "The FillInTheGaps" (FillInTheGaps.makeComponent)
17− [ { initialSegments: parseSegments codeWithHoles ?|| [], update: pure (pure unit) }
17+ [ { initialSegments: parseSegments codeWithHoles ?|| [], incantate: pure (pure unit) }
1818 ]
1919
2020codeWithHoles =