git.iko.soy/rowtype-yoga/psfp
on master help sign in
Ja mit Faylern!
659e174Mark Eibes
blog/.psc-ide-portnew file+1
@@ -0,0 +1 @@
1+15530
blog/src/components/FillInTheGaps.pursnew file+54
@@ -0,0 +1,54 @@
1+module FillInTheGaps where
2+
3+import Prelude
4+
5+import Data.Array as A
6+import Data.Maybe (Maybe(..), fromMaybe)
7+import Data.String (Pattern(..), split)
8+import Data.Tuple.Nested ((/\))
9+import Effect (Effect)
10+import Effect.Unsafe (unsafePerformEffect)
11+import Justifill (justifill)
12+import Partial.Unsafe (unsafeCrashWith)
13+import React.Basic (JSX, ReactComponent, element)
14+import React.Basic.DOM as R
15+import React.Basic.Hooks (ReactChildren, componentWithChildren, reactChildrenToArray, useState)
16+import React.Basic.Hooks as React
17+import Yoga.InlineCode.Component as InlineCode
18+
19+data Segment = Filler String | Hole String
20+
21+renderSegments :: ReactComponent InlineCode.Props -> ((Array (Array Segment) -> Array (Array Segment)) -> Effect Unit) -> Array (Array Segment) -> JSX
22+renderSegments ic update arrs = R.div_ (arrs `flip A.mapWithIndex` renderLine)
23+ where
24+ renderLine i l = R.div_ (l `flip A.mapWithIndex` renderSegment i)
25+ renderSegment i j = case _ of
26+ Filler s -> R.span_ [R.text s]
27+ Hole _ -> element ic $ justifill { onSubmit: \s -> update (updateSegments i j s) }
28+
29+updateSegments :: Int -> Int -> String -> Array (Array Segment) -> Array (Array Segment)
30+updateSegments i j v arrs = fromMaybe [] (A.modifyAt i (updateLine j v) arrs)
31+
32+updateLine :: Int -> String -> Array Segment -> Array Segment
33+updateLine idx v arr = fromMaybe [] (A.modifyAt idx f arr)
34+ where
35+ f = case _ of
36+ Filler s -> unsafeCrashWith "Updated a filler"
37+ Hole _ -> Hole v
38+
39+
40+fillInTheGaps :: ReactComponent { children :: ReactChildren String }
41+fillInTheGaps = unsafePerformEffect do
42+ ic <- InlineCode.makeComponent
43+ componentWithChildren "InlineCodeWithChildren" \{ children } -> React.do
44+ let
45+ separator = "???"
46+ child = children # reactChildrenToArray # A.head # fromMaybe "gurki"
47+ lines = split (Pattern "\n") child
48+ rawSegments = split (Pattern separator)
49+ toSegment = case _ of
50+ x | x == separator -> Hole ""
51+ other -> Filler other
52+ initialSegments = lines <#> \line -> rawSegments line <#> toSegment
53+ (segments :: Array (Array Segment)) /\ modifySegments <- useState initialSegments
54+ pure $ renderSegments ic (modifySegments) segments
blog/src/components/PSLayout.purs+6−2
@@ -4,9 +4,11 @@ import Prelude
4
4
5import Color (toHexString)
5import Color (toHexString)
6import Data.Array as Array
6import Data.Array as Array
7+import Data.Array.NonEmpty as NEA
7import Data.Maybe (Maybe(..), fromMaybe)
8import Data.Maybe (Maybe(..), fromMaybe)
8import Data.Nullable (Nullable)
9import Data.Nullable (Nullable)
9import Data.Nullable as Nullable
10import Data.Nullable as Nullable
11+import Data.Semigroup.Foldable (intercalateMap)
10import Data.String as String
12import Data.String as String
11import Effect (Effect)
13import Effect (Effect)
12import JSS (jss, jssClasses)
14import JSS (jss, jssClasses)
@@ -20,6 +22,7 @@ import React.Basic.Hooks (ReactChildren, component, componentWithChildren, eleme
20import React.Basic.Hooks as React
22import React.Basic.Hooks as React
21import Yoga.CompileEditor.Component (mkCompileEditor)
23import Yoga.CompileEditor.Component (mkCompileEditor)
22import Yoga.Header.Component (mkHeader)
24import Yoga.Header.Component (mkHeader)
25+import Yoga.InlineCode.Component as InlineCode
23import Yoga.Theme (fromTheme)
26import Yoga.Theme (fromTheme)
24import Yoga.Theme.CSSBaseline (mkCssBaseline)
27import Yoga.Theme.CSSBaseline (mkCssBaseline)
25import Yoga.Theme.Default (darkTheme)
28import Yoga.Theme.Default (darkTheme)
@@ -87,14 +90,15 @@ mkMdxProviderComponent fetchImpl = do
87 editor <- mkCompileEditor fetchImpl
90 editor <- mkCompileEditor fetchImpl
88 sidebar <- mkSidebar
91 sidebar <- mkSidebar
89 header <- mkHeader
92 header <- mkHeader
93+ yogaInlineCode <- InlineCode.makeComponent
90 h <- mkH
94 h <- mkH
91 p <- mkP
95 p <- mkP
92 useStyles <-
96 useStyles <-
93 makeStylesJSS
97 makeStylesJSS
94 $ jssClasses \(theme ∷ CSSTheme) ->
98 $ jssClasses \(theme ∷ CSSTheme) ->
95 { code:
99 { code:
96− { fontFamily: theme.codeFontFamily
100+ { fontFamily: theme.codeFontFamily # NEA.head
97− , backgroundColor: toHexString $ theme.interfaceColour
101+ , backgroundColor: theme.interfaceColour
98 , fontSize: "10pt"
102 , fontSize: "10pt"
99 , border: "1px solid #383c39"
103 , border: "1px solid #383c39"
100 , padding: "3px"
104 , padding: "3px"
blog/src/components/fillInTheGaps.jsnew file+2
@@ -0,0 +1,2 @@
1+const FillInTheGaps = require("./FillInTheGaps.purs").fillInTheGaps
2+export default FillInTheGaps;
blog/src/pages/index.mdx+1−1
@@ -22,5 +22,5 @@ heinz = 7
22This is some `inline code`.
22This is some `inline code`.
23
23
24Now go build something great.
24Now go build something great.
25−<Link to="/page-2/">Go to page 2</Link>
25+<Link to="/optional/">Go to the first exercise</Link>
26
26
blog/src/pages/optional.mdxnew file+17
@@ -0,0 +1,17 @@
1+import Layout from '../components/layout'
2+import SEO from '../components/seo'
3+import FillInTheGaps from '../components/fillInTheGaps'
4+
5+<SEO title="Home" keywords={['gatsby', 'application', 'react']} />
6+
7+# Optional
8+
9+<div>Udo</div>
10+<FillInTheGaps>module Main where
11+import Batteries
12+
13+main :: Effect Unit
14+main = log "???"
15+</FillInTheGaps>
16+
17+## Hans Hölzel
blog/src/pages/page-2.mdxdeleted−11
@@ -1,11 +0,0 @@
1−import { Link } from 'gatsby'
2−import Layout from '../components/layout'
3−import SEO from '../components/seo'
4−
5−<SEO title="Page two" />
6−
7−# Hi from the second page
8−
9−Welcome to page 2
10−
11−<Link to="/">Go back to the homepage</Link>
components/src/Yoga/InlineCode/Component.purs+3−9
@@ -24,12 +24,8 @@ type Props
24type PropsR
24type PropsR
25 = OptionalProps (Styles.PropsR)
25 = OptionalProps (Styles.PropsR)
26
26
27−data Action
28− = CompileAndRunCode String
29−
30−derive instance eqAction ∷ Eq Action
31type OptionalProps r
27type OptionalProps r
32− = ( dispatch ∷ Action -> Effect Unit
28+ = ( onSubmit ∷ String -> Effect Unit
33 , className ∷ Maybe String
29 , className ∷ Maybe String
34 | r
30 | r
35 )
31 )
@@ -37,7 +33,7 @@ type OptionalProps r
37makeComponent ∷ Effect (ReactComponent Props)
33makeComponent ∷ Effect (ReactComponent Props)
38makeComponent = do
34makeComponent = do
39 useStyles <- makeStylesJSS styles
35 useStyles <- makeStylesJSS styles
40− component "InlineCode" \props@{ className, dispatch } -> React.do
36+ component "InlineCode" \props@{ className, onSubmit } -> React.do
41 value /\ modifyValue <- useState ""
37 value /\ modifyValue <- useState ""
42 classes <- useStyles $ pick props
38 classes <- useStyles $ pick props
43 pure
39 pure
@@ -55,7 +51,5 @@ makeComponent = do
55 , _data: Obj.singleton "testid" "inline-code"
51 , _data: Obj.singleton "testid" "inline-code"
56 }
52 }
57 ]
53 ]
58− , onSubmit:
59− handler preventDefault
54+ , onSubmit: handler preventDefault (const $ onSubmit value)
60− (const $ dispatch $ CompileAndRunCode value)
61 }
55 }
components/src/Yoga/InlineCode/Spec.purs+3−3
@@ -42,12 +42,12 @@ spec =
42 refContent `shouldEqual` "Heinzelmän"
42 refContent `shouldEqual` "Heinzelmän"
43
43
44data Action
44data Action
45− = InlineCodeAction InlineCode.Action
45+ = InlineCodeAction String
46
46
47derive instance eqAction ∷ Eq Action
47derive instance eqAction ∷ Eq Action
48mkReducer ∷ Ref String -> Maybe String -> Action -> Aff (Maybe String)
48mkReducer ∷ Ref String -> Maybe String -> Action -> Aff (Maybe String)
49mkReducer ref state = case _ of
49mkReducer ref state = case _ of
50− InlineCodeAction (InlineCode.CompileAndRunCode s) -> do
50+ InlineCodeAction s -> do
51 Ref.write s ref # liftEffect
51 Ref.write s ref # liftEffect
52 pure state
52 pure state
53
53
@@ -60,6 +60,6 @@ mkWrapper = do
60 pure
60 pure
61 $ element inlineCode
61 $ element inlineCode
62 ( justifill
62 ( justifill
63− { dispatch: dispatch <<< InlineCodeAction
63+ { onSubmit: dispatch <<< InlineCodeAction
64 }
64 }
65 )
65 )
components/src/Yoga/InlineCode/Stories.purs+7−8
@@ -9,7 +9,7 @@ import Data.String.CodeUnits as String
9import Data.Tuple.Nested ((/\))
9import Data.Tuple.Nested ((/\))
10import Effect (Effect)
10import Effect (Effect)
11import Effect.Aff (Aff)
11import Effect.Aff (Aff)
12−import Effect.Class.Console (log)
12+import Effect.Console (log)
13import Justifill (justifill)
13import Justifill (justifill)
14import Milkis as M
14import Milkis as M
15import Milkis.Impl.Window (windowFetch)
15import Milkis.Impl.Window (windowFetch)
@@ -22,7 +22,6 @@ import React.Basic.Hooks as React
22import Storybook.Decorator.FullScreen (fullScreenDecorator)
22import Storybook.Decorator.FullScreen (fullScreenDecorator)
23import Storybook.React (Storybook, add, addDecorator, storiesOf)
23import Storybook.React (Storybook, add, addDecorator, storiesOf)
24import Yoga.CompileEditor.Component (compileAndRun)
24import Yoga.CompileEditor.Component (compileAndRun)
25−import Yoga.InlineCode.Component (Action(..))
26import Yoga.InlineCode.Component as InlineCode
25import Yoga.InlineCode.Component as InlineCode
27import Yoga.Modal.Component as Modal
26import Yoga.Modal.Component as Modal
28
27
@@ -32,7 +31,7 @@ stories = do
32 addDecorator fullScreenDecorator
31 addDecorator fullScreenDecorator
33 add "The InlineCode" InlineCode.makeComponent
32 add "The InlineCode" InlineCode.makeComponent
34 [ ( justifill
33 [ ( justifill
35− { dispatch: \(_ ∷ InlineCode.Action) -> ((log "hi") ∷ Effect Unit)
34+ { onSubmit: log
36 }
35 }
37 )
36 )
38 ]
37 ]
@@ -40,7 +39,7 @@ stories = do
40 [ { inside:
39 [ { inside:
41 \inlineCode ->
40 \inlineCode ->
42 [ R.text "hi!"
41 [ R.text "hi!"
43− , element inlineCode (justifill { dispatch: \(_ ∷ InlineCode.Action) -> (log "Hi") ∷ Effect Unit })
42+ , element inlineCode (justifill { onSubmit: log })
44 , R.text "hello again!"
43 , R.text "hello again!"
45 ]
44 ]
46 }
45 }
@@ -49,7 +48,7 @@ stories = do
49 [ { inside:
48 [ { inside:
50 \inlineCode ->
49 \inlineCode ->
51 [ R.code_ [ R.text "main = logShow \"" ]
50 [ R.code_ [ R.text "main = logShow \"" ]
52− , element inlineCode (justifill { dispatch: \(_ ∷ InlineCode.Action) -> (log "Hi") ∷ Effect Unit })
51+ , element inlineCode (justifill { onSubmit: log })
53 , R.code_ [ R.text "\"" ]
52 , R.code_ [ R.text "\"" ]
54 ]
53 ]
55 }
54 }
@@ -84,7 +83,7 @@ type State
84 = Maybe Boolean
83 = Maybe Boolean
85
84
86data RealAction
85data RealAction
87− = InlineCodeAction InlineCode.Action
86+ = InlineCodeSubmitted String
88 | CloseModal
87 | CloseModal
89
88
90derive instance eqRealAction ∷ Eq RealAction
89derive instance eqRealAction ∷ Eq RealAction
@@ -98,7 +97,7 @@ mkRealWrapper = do
98 $ R.div_
97 $ R.div_
99 [ R.h2_ [ R.text "Let's log some 'Magick'" ]
98 [ R.h2_ [ R.text "Let's log some 'Magick'" ]
100 , fragment $ renderCode codePrefix
99 , fragment $ renderCode codePrefix
101− , element inlineCode (justifill { dispatch: dispatch <<< InlineCodeAction, width: String.length "Magick" })
100+ , element inlineCode (justifill { onSubmit: dispatch <<< InlineCodeSubmitted, width: String.length "Magick" })
102 , fragment $ renderCode codeSuffix
101 , fragment $ renderCode codeSuffix
103 , R.br {}
102 , R.br {}
104 , case state of
103 , case state of
@@ -110,7 +109,7 @@ mkRealWrapper = do
110realReducer ∷ State -> RealAction -> Aff State
109realReducer ∷ State -> RealAction -> Aff State
111realReducer state = case _ of
110realReducer state = case _ of
112 CloseModal -> pure Nothing
111 CloseModal -> pure Nothing
113− InlineCodeAction (CompileAndRunCode code) -> do
112+ InlineCodeSubmitted code -> do
114 res <- compileAndRun (M.fetch windowFetch) { code: codePrefix <> code <> codeSuffix }
113 res <- compileAndRun (M.fetch windowFetch) { code: codePrefix <> code <> codeSuffix }
115 (pure <<< pure) case res of
114 (pure <<< pure) case res of
116 Right { stdout }
115 Right { stdout }