@@ -1,17 +1,20 @@
1module PSLayout where
1module PSLayout where
3import Prelude
3import Prelude
5+import Data.Array (foldMap)
4import Data.Array as A
6import Data.Array as A
5import Data.Array as Array
7import Data.Array as Array
6import Data.Array.NonEmpty as NEA
8import Data.Array.NonEmpty as NEA
7−import Data.Function.Uncurried (mkFn2)
9+import Data.Either (Either(..))
8import Data.Maybe (Maybe(..), fromMaybe, isJust)
10import Data.Maybe (Maybe(..), fromMaybe, isJust)
9−import Data.Nullable (Nullable, toMaybe)
11+import Data.Nullable (Nullable)
10import Data.Nullable as Nullable
12import Data.Nullable as Nullable
11import Data.String as String
13import Data.String as String
12import Data.Tuple.Nested ((/\))
14import Data.Tuple.Nested ((/\))
13−import Debug.Trace (spy)
14import Effect (Effect)
15import Effect (Effect)
16+import Effect.Aff (launchAff_)
17+import Effect.Class (liftEffect)
15import JSS (jss, jssClasses)
18import JSS (jss, jssClasses)
16import Justifill (justifill)
19import Justifill (justifill)
17import Milkis.Impl (FetchImpl)
20import Milkis.Impl (FetchImpl)
@@ -23,14 +26,16 @@ import React.Basic.Hooks (ReactChildren, component, componentWithChildren, eleme
23import React.Basic.Hooks as React
26import React.Basic.Hooks as React
24import Unsafe.Coerce (unsafeCoerce)
27import Unsafe.Coerce (unsafeCoerce)
25import Yoga.Box.Component as Box
28import Yoga.Box.Component as Box
29+import Yoga.ClickAway.Component as ClickAway
26import Yoga.CompileEditor.Component (mkCompileEditor)
30import Yoga.CompileEditor.Component (mkCompileEditor)
27import Yoga.Compiler.Api (apiCompiler)
31import Yoga.Compiler.Api (apiCompiler)
28import Yoga.Compiler.Types (Compiler)
32import Yoga.Compiler.Types (Compiler)
29import Yoga.FillInTheGaps.Component as FillInTheGaps
33import Yoga.FillInTheGaps.Component as FillInTheGaps
30−import Yoga.FillInTheGaps.Logic (complete, parseSegments)
34+import Yoga.FillInTheGaps.Logic (findResult, parseSegments, toCode)
31import Yoga.Header.Component (mkHeader)
35import Yoga.Header.Component (mkHeader)
32import Yoga.Helpers ((?||))
36import Yoga.Helpers ((?||))
33import Yoga.InlineCode.Component as InlineCode
37import Yoga.InlineCode.Component as InlineCode
38+import Yoga.Modal.Component as Modal
34import Yoga.Theme (fromTheme)
39import Yoga.Theme (fromTheme)
35import Yoga.Theme.CSSBaseline (mkCssBaseline)
40import Yoga.Theme.CSSBaseline (mkCssBaseline)
36import Yoga.Theme.Default (darkTheme)
41import Yoga.Theme.Default (darkTheme)
@@ -97,6 +102,13 @@ mkSecret = do
97 , children: kids
102 , children: kids
105+isQuiz ∷ JSX -> Boolean
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)
100mkMdxProviderComponent ∷
112mkMdxProviderComponent ∷
102 { | Compiler r } ->
114 { | Compiler r } ->
@@ -114,6 +126,8 @@ mkMdxProviderComponent compiler = do
114 sidebar <- mkSidebar
126 sidebar <- mkSidebar
115 header <- mkHeader
127 header <- mkHeader
116 yogaInlineCode <- InlineCode.makeComponent
128 yogaInlineCode <- InlineCode.makeComponent
129+ modal <- Modal.makeComponent
130+ clickAway <- ClickAway.makeComponent
119 secret <- mkSecret
133 secret <- mkSecret
@@ -136,6 +150,8 @@ mkMdxProviderComponent compiler = do
136 componentWithChildren "MDXProviderComponent" \{ children, siteInfo } -> React.do
150 componentWithChildren "MDXProviderComponent" \{ children, siteInfo } -> React.do
137 classes <- useStyles {}
151 classes <- useStyles {}
138 visibleThrough /\ updateVisible <- useState 1
152 visibleThrough /\ updateVisible <- useState 1
153+ questions /\ updateQuestions <- useState []
154+ maybeModal /\ updateModal <- useState Nothing
140 baseline child = element cssBaseline { kids: child }
156 baseline child = element cssBaseline { kids: child }
@@ -146,10 +162,7 @@ mkMdxProviderComponent compiler = do
146 if i >= visibleThrough then
162 if i >= visibleThrough then
147 { i, acc }
163 { i, acc }
149− if (unsafeCoerce a).props.mdxType == "pre"
165+ if isQuiz a then
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
153 { i: i + 1, acc: A.snoc acc a }
166 { i: i + 1, acc: A.snoc acc a }
155 { i, acc: A.snoc acc a }
168 { i, acc: A.snoc acc a }
@@ -218,11 +231,14 @@ mkMdxProviderComponent compiler = do
218 jsx box {}
231 jsx box {}
219 [ element fillInTheGaps
232 [ element fillInTheGaps
220 { initialSegments
233 { initialSegments
221− , update:
234+ , incantate: \segments -> launchAff_ do
222− \segs ->
235+ let code = toCode segments
223− when (complete segs)
236+ result <- compiler.compileAndRun { code }
237+ liftEffect case result of
238+ Right r | String.stripSuffix (String.Pattern "\n") r.stdout == (findResult $ join segments) ->
224− $ updateVisible
239+ updateVisible (_ + 1)
241+ updateModal (const $ Just { title: "Failed", kids: [R.text "Try again"] })
228 true, _, _ ->
244 true, _, _ ->
@@ -241,6 +257,13 @@ mkMdxProviderComponent compiler = do
242 , components: mdxComponents
258 , components: mdxComponents
260+ , maybeModal # foldMap
263+ element clickAway { allowEscape: Just true, onClick: updateModal (const Nothing), style: Nothing },
264+ element modal (justifill modalProps)
246mkSidebar = do
269mkSidebar = do