git.iko.soy/rowtype-yoga/psfp
on master help sign in
Ronnie's Würstchenbude
3664c84Mark Eibes
components/src/React/Basic/Extra/Hooks/UseAffReducer.purs+6−6
@@ -26,12 +26,12 @@ useAffReducer initialState reducer =
26 coerceHook React.do
26 coerceHook React.do
27 state /\ modifyState <- useState initialState
27 state /\ modifyState <- useState initialState
28 maybeAction /\ modifyAction <- useState Nothing
28 maybeAction /\ modifyAction <- useState Nothing
29+ useAff maybeAction do
30+ for_ maybeAction \action -> do
31+ newState <- reducer state action
32+ liftEffect do
33+ modifyState (const newState)
34+ modifyAction (const Nothing)
29 let
35 let
30 dispatch = modifyAction <<< const <<< Just
36 dispatch = modifyAction <<< const <<< Just
31− useAff maybeAction
32− $ for_ maybeAction \action -> do
33− newState <- reducer state action
34− liftEffect do
35− modifyState (const newState)
36− modifyAction (const Nothing)
37 pure (state /\ dispatch)
37 pure (state /\ dispatch)
components/src/Yoga/Button/Component.purs+2−1
@@ -3,6 +3,7 @@ module Yoga.Button.Component where
3import Prelude
3import Prelude
4import CSS (Color, cssStringRGBA, desaturate)
4import CSS (Color, cssStringRGBA, desaturate)
5import CSS as Color
5import CSS as Color
6+import Data.Array.NonEmpty as NEA
6import Data.Foldable (intercalate)
7import Data.Foldable (intercalate)
7import Data.Interpolate (i)
8import Data.Interpolate (i)
8import Data.Maybe (Maybe)
9import Data.Maybe (Maybe)
@@ -106,7 +107,7 @@ styles =
106 , border: "0"
107 , border: "0"
107 , height: "calc(var(--s2))"
108 , height: "calc(var(--s2))"
108 , fontSize: "calc(var(--s-1))"
109 , fontSize: "calc(var(--s-1))"
109− , fontFamily: theme.textFontFamily
110+ , fontFamily: NEA.head theme.textFontFamily
110 , fontWeight: "600"
111 , fontWeight: "600"
111 , padding: "0 var(--s0) 0 var(--s0)"
112 , padding: "0 var(--s0) 0 var(--s0)"
112 , letterSpacing: "var(--s-5)"
113 , letterSpacing: "var(--s-5)"
components/src/Yoga/Header/Component.purs−1
@@ -30,7 +30,6 @@ mkHeader = do
30 , borderRight: "1px solid " <> (theme.backgroundColourLightest # toHexString)
30 , borderRight: "1px solid " <> (theme.backgroundColourLightest # toHexString)
31 , borderLeft: "1px solid " <> (theme.backgroundColourLightest # toHexString)
31 , borderLeft: "1px solid " <> (theme.backgroundColourLightest # toHexString)
32 , color: theme.textColour # toHexString
32 , color: theme.textColour # toHexString
33− , fontFamily: theme.textFontFamily
34 , fontSize: "2em"
33 , fontSize: "2em"
35 , padding: "20px"
34 , padding: "20px"
36 , display: "flex"
35 , display: "flex"
components/src/Yoga/Helpers.purs+1−1
@@ -6,7 +6,7 @@ import Data.Maybe (Maybe(..), fromMaybe)
6fromMaybeFlipped ∷ ∀ a. Maybe a -> a -> a
6fromMaybeFlipped ∷ ∀ a. Maybe a -> a -> a
7fromMaybeFlipped = flip fromMaybe
7fromMaybeFlipped = flip fromMaybe
8
8
9−infixr 7 fromMaybeFlipped as ?||
9+infixr 5 fromMaybeFlipped as ?||
10
10
11ifJustTrue ∷ ∀ m. Monoid m => Maybe Boolean -> m -> m
11ifJustTrue ∷ ∀ m. Monoid m => Maybe Boolean -> m -> m
12ifJustTrue option value = if option == Just true then value else mempty
12ifJustTrue option value = if option == Just true then value else mempty
components/src/Yoga/InlineCode/Component.purs+4−2
@@ -3,9 +3,9 @@ module Yoga.InlineCode.Component where
3import Prelude
3import Prelude
4import Data.Foldable (fold, intercalate)
4import Data.Foldable (fold, intercalate)
5import Data.Maybe (Maybe)
5import Data.Maybe (Maybe)
6+import Data.String (trim)
6import Data.Tuple.Nested ((/\))
7import Data.Tuple.Nested ((/\))
7import Effect (Effect)
8import Effect (Effect)
8−import Effect.Class.Console (log)
9import Foreign.Object as Obj
9import Foreign.Object as Obj
10import React.Basic.DOM as R
10import React.Basic.DOM as R
11import React.Basic.DOM.Events (preventDefault, targetValue)
11import React.Basic.DOM.Events (preventDefault, targetValue)
@@ -42,9 +42,11 @@ makeComponent = do
42 classes <- useStyles $ pick props
42 classes <- useStyles $ pick props
43 pure
43 pure
44 $ R.form
44 $ R.form
45+ { className: classes.form
45− { children:
46+ , children:
46 [ R.input
47 [ R.input
47 { className: intercalate " " [ classes.inlinecode, fold className ]
48 { className: intercalate " " [ classes.inlinecode, fold className ]
49+ , maxLength: props.width ?|| 10
48 , value
50 , value
49 , onChange:
51 , onChange:
50 handler targetValue
52 handler targetValue
components/src/Yoga/InlineCode/Spec.purs+5−3
@@ -8,6 +8,7 @@ import Effect.Aff (Aff)
8import Effect.Class (liftEffect)
8import Effect.Class (liftEffect)
9import Effect.Ref (Ref)
9import Effect.Ref (Ref)
10import Effect.Ref as Ref
10import Effect.Ref as Ref
11+import Justifill (justifill)
11import React.Basic.Extra.Hooks (useAffReducer)
12import React.Basic.Extra.Hooks (useAffReducer)
12import React.Basic.Hooks (ReactComponent, component, element, useEffect)
13import React.Basic.Hooks (ReactComponent, component, element, useEffect)
13import React.Basic.Hooks as React
14import React.Basic.Hooks as React
@@ -57,6 +58,7 @@ mkWrapper = do
57 useEffect state mempty
58 useEffect state mempty
58 pure
59 pure
59 $ element inlineCode
60 $ element inlineCode
61+ ( justifill
60− { dispatch: dispatch <<< InlineCodeAction
62+ { dispatch: dispatch <<< InlineCodeAction
61− , className: Nothing
62− }
63+ }
64+ )
components/src/Yoga/InlineCode/Stories.purs+98−2
@@ -1,20 +1,116 @@
1module Yoga.InlineCode.Stories where
1module Yoga.InlineCode.Stories where
2
2
3import Prelude hiding (add)
3import Prelude hiding (add)
4+import Data.Array (intercalate, length)
5+import Data.Either (Either(..))
4import Data.Maybe (Maybe(..))
6import Data.Maybe (Maybe(..))
7+import Data.String (Pattern(..), split, trim)
8+import Data.String.CodeUnits as String
9+import Data.Tuple.Nested ((/\))
10+import Debug.Trace (spy)
5import Effect (Effect)
11import Effect (Effect)
12+import Effect.Aff (Aff)
6import Effect.Class.Console (log)
13import Effect.Class.Console (log)
14+import Justifill (justifill)
15+import Milkis as M
16+import Milkis.Impl.Window (windowFetch)
17+import React.Basic (JSX, fragment)
7import React.Basic.DOM as R
18import React.Basic.DOM as R
19+import React.Basic.Extra.Hooks (useAffReducer)
20+import React.Basic.Helpers (jsx)
21+import React.Basic.Hooks (ReactComponent, component, element)
22+import React.Basic.Hooks as React
8import Storybook.Decorator.FullScreen (fullScreenDecorator)
23import Storybook.Decorator.FullScreen (fullScreenDecorator)
9import Storybook.React (Storybook, add, addDecorator, storiesOf)
24import Storybook.React (Storybook, add, addDecorator, storiesOf)
25+import Yoga.CompileEditor.Component (compileAndRun)
26+import Yoga.InlineCode.Component (Action(..))
10import Yoga.InlineCode.Component as InlineCode
27import Yoga.InlineCode.Component as InlineCode
28+import Yoga.Modal.Component as Modal
11
29
12stories ∷ Effect Storybook
30stories ∷ Effect Storybook
13stories = do
31stories = do
14 storiesOf "InlineCode" do
32 storiesOf "InlineCode" do
15 addDecorator fullScreenDecorator
33 addDecorator fullScreenDecorator
16 add "The InlineCode" InlineCode.makeComponent
34 add "The InlineCode" InlineCode.makeComponent
35+ [ ( justifill
17− [ { dispatch: const $ log "hi"
36+ { dispatch: \(_ ∷ InlineCode.Action) -> ((log "hi") ∷ Effect Unit)
18− , className: Nothing
37+ }
38+ )
39+ ]
40+ add "The InlineCode with some context" mkWrapper
41+ [ { inside:
42+ \inlineCode ->
43+ [ R.text "hi!"
44+ , element inlineCode (justifill { dispatch: \(_ ∷ InlineCode.Action) -> (log "Hi") ∷ Effect Unit })
45+ , R.text "hello again!"
46+ ]
47+ }
48+ ]
49+ add "The InlineCode with some code" mkWrapper
50+ [ { inside:
51+ \inlineCode ->
52+ [ R.code_ [ R.text "main = logShow \"" ]
53+ , element inlineCode (justifill { dispatch: \(_ ∷ InlineCode.Action) -> (log "Hi") ∷ Effect Unit })
54+ , R.code_ [ R.text "\"" ]
55+ ]
19 }
56 }
20 ]
57 ]
58+ add "The InlineCode with some real code" mkRealWrapper
59+ [ {} ]
60+
61+codePrefix =
62+ """module Main where
63+import Batteries
64+
65+main = log """"
66+
67+codeSuffix = "\""
68+
69+renderCode c = intercalate [ R.br {} ] (toJSX <$> lines)
70+ where
71+ toJSX line = [ R.code_ [ R.text line ] ]
72+ lines = split (Pattern "\n") c
73+
74+mkWrapper ∷ Effect (ReactComponent { inside ∷ ReactComponent InlineCode.Props -> Array JSX })
75+mkWrapper = do
76+ inlineCode <- InlineCode.makeComponent
77+ component "InlineCodeWrapper" \{ inside } -> React.do
78+ pure
79+ $ R.div_ (inside inlineCode)
80+
81+type State
82+ = Maybe Boolean
83+
84+data RealAction
85+ = InlineCodeAction InlineCode.Action
86+ | CloseModal
87+
88+derive instance eqRealAction ∷ Eq RealAction
89+mkRealWrapper ∷ Effect (ReactComponent {})
90+mkRealWrapper = do
91+ inlineCode <- InlineCode.makeComponent
92+ modal <- Modal.makeComponent
93+ component "InlineCodeWrapper" \{} -> React.do
94+ state /\ dispatch <- useAffReducer Nothing realReducer
95+ pure
96+ $ R.div_
97+ [ R.h2_ [ R.text "Let's log some 'Magick'" ]
98+ , fragment $ renderCode codePrefix
99+ , element inlineCode (justifill { dispatch: dispatch <<< InlineCodeAction, width: String.length "Magick" })
100+ , fragment $ renderCode codeSuffix
101+ , R.br {}
102+ , case state of
103+ Just true -> element modal $ justifill { title: "Success!", content: R.text "You did it!", onClose: dispatch CloseModal }
104+ Just false -> element modal $ justifill { title: "Oh no!", content: R.text "Try again!", onClose: dispatch CloseModal }
105+ Nothing -> mempty
106+ ]
107+
108+realReducer ∷ State -> RealAction -> Aff State
109+realReducer state = case _ of
110+ CloseModal -> pure Nothing
111+ InlineCodeAction (CompileAndRunCode code) -> do
112+ res <- compileAndRun (M.fetch windowFetch) { code: codePrefix <> code <> codeSuffix }
113+ (pure <<< Just) case spy "res" res of
114+ Right { stdout }
115+ | String.dropRight 1 stdout == "Magick" -> true
116+ _ -> false
components/src/Yoga/InlineCode/Styles.purs+59−7
@@ -1,11 +1,27 @@
1module Yoga.InlineCode.Styles where
1module Yoga.InlineCode.Styles where
2
2
3import Prelude
3import Prelude
4+import CSS (GenericFontFamily(..), Selector, TimingFunction(..), animation, background, border, borderBottom, borderBox, borderRadius, boxSizing, color, darken, display, element, focus, fontFamily, fontSize, fromString, inlineBlock, iterationCount, keyframes, lighten, lineHeight, nil, padding, sec, solid, transform, transition, unitless, width, (!*), (!+), (&), (?))
5+import CSS.Animation (forwards, normalAnimationDirection)
6+import CSS.Common (baseline, middle)
7+import CSS.Overflow (hidden, overflow, visible)
8+import CSS.Size (ch)
9+import CSS.Transform (scale3d)
10+import CSS.VerticalAlign (verticalAlign)
11+import Color as Color
12+import Data.Array.NonEmpty as NEA
13+import Data.Int (toNumber)
14+import Data.Maybe (Maybe)
15+import Data.NonEmpty (NonEmpty(..), (:|))
16+import Data.Tuple.Nested ((/\))
4−import JSS (JSSClasses, JSSElem, jssClasses)
17+import JSS (JSSClasses, JSSElem, jss, jssClasses)
18+import Yoga.Helpers ((?||))
19+import Yoga.Theme (withAlpha)
5−import Yoga.Theme.Types (YogaTheme)
20+import Yoga.Theme.Types (YogaTheme, CSSTheme)
6
21
7type PropsR
22type PropsR
8− = (
23+ = ( regularFont ∷ Maybe Boolean
24+ , width ∷ Maybe Int
9 )
25 )
10
26
11type Props
27type Props
@@ -14,10 +30,46 @@ type Props
14styles ∷
30styles ∷
15 JSSClasses YogaTheme Props
31 JSSClasses YogaTheme Props
16 ( inlinecode ∷ JSSElem Props
32 ( inlinecode ∷ JSSElem Props
33+ , form ∷ JSSElem Props
34+ , "@keyframes plop" ∷ JSSElem Props
17 )
35 )
18−styles =
19− jssClasses \theme ->
36+styles = jssClasses go
37+ where
38+ go (theme@{ s0, s1, s_1, s_2, s_3, s_4, s_5 } ∷ CSSTheme) =
39+ { form:
40+ do
41+ display inlineBlock
42+ , "@keyframes plop":
43+ keyframes mempty
44+ $ (0.0 /\ transform (scale3d 0.8 0.8 0.8))
45+ :| [ 33.3 /\ transform (scale3d 1.1 1.1 1.1)
46+ , 67.7 /\ transform (scale3d 0.9 0.9 0.9)
47+ , 86.7 /\ transform (scale3d 1.05 1.05 1.05)
48+ , 100.0 /\ transform (scale3d 1.0 1.0 1.0)
49+ ]
20− { inlinecode:
50+ , inlinecode:
21 \props ->
51 \props ->
22− {}
52+ jss { outline: "none" }
53+ <> jss do
54+ overflow visible
55+ boxSizing borderBox
56+ verticalAlign baseline
57+ background $ withAlpha 0.15 theme.textColour
58+ border solid s_5 (Color.rgba 0 0 0 0.0)
59+ borderRadius s_2 s_2 s_2 s_2
60+ fontFamily
61+ (NEA.toArray theme.codeFontFamily)
62+ (NonEmpty (GenericFontFamily $ fromString "monospace") [])
63+ fontSize (s0)
64+ lineHeight (s0)
65+ width $ (props.width ?|| 10 # toNumber # ch) !+ (unitless 4.2 !* s_5)
66+ padding nil s_5 nil s_5
67+ color theme.textColour
68+ this & focus
69+ ? do
70+ animation (fromString "$plop") (0.3 # sec) EaseIn (0.0 # sec) (1.0 # iterationCount) normalAnimationDirection forwards
71+ border solid s_5 theme.highlightColourRotatedBackwards
23 }
72 }
73+
74+this ∷ Selector
75+this = element "&"
components/src/Yoga/JSS.purs+16−4
@@ -1,9 +1,11 @@
1module JSS where
1module JSS where
2
2
3import Prelude
3import Prelude
4−import CSS (Color, Key(..), Rule(..), StyleM, Value(..), cssStringRGBA, plain, runS)
4+import CSS (App(..), Color, Key(..), Keyframes(..), Path(..), Predicate(..), Refinement(..), Rule(..), Selector(..), StyleM, Value(..), cssStringRGBA, plain, predicate, runS)
5import Data.Foldable (foldMap)
5import Data.Foldable (foldMap)
6+import Data.Int (round)
6import Data.Symbol (class IsSymbol, SProxy(..), reflectSymbol)
7import Data.Symbol (class IsSymbol, SProxy(..), reflectSymbol)
8+import Data.Tuple (Tuple(..))
7import Debug.Trace (spy)
9import Debug.Trace (spy)
8import Foreign (unsafeToForeign)
10import Foreign (unsafeToForeign)
9import Foreign.Object (Object)
11import Foreign.Object (Object)
@@ -51,6 +53,8 @@ data JSSElem props
51
53
52instance semigroupJssElem ∷ Semigroup (JSSElem props) where
54instance semigroupJssElem ∷ Semigroup (JSSElem props) where
53 append = case _, _ of
55 append = case _, _ of
56+ PrimitiveJss p1, PrimitiveJss p2
57+ | p1 == p2 -> PrimitiveJss p1
54 NestedJss n1, NestedJss n2 -> NestedJss (n1 <> n2)
58 NestedJss n1, NestedJss n2 -> NestedJss (n1 <> n2)
55 ArrayJss a1, ArrayJss a2 -> ArrayJss (a1 <> a2)
59 ArrayJss a1, ArrayJss a2 -> ArrayJss (a1 <> a2)
56 NestedJss n1, PropsJss fn ->
60 NestedJss n1, PropsJss fn ->
@@ -59,23 +63,24 @@ instance semigroupJssElem ∷ Semigroup (JSSElem props) where
59 other -> do
63 other -> do
60 let
64 let
61 _ = spy "other" other
65 _ = spy "other" other
62− unsafeCrashWith "Untreated branch, fix me"
66+ unsafeCrashWith "Untreated branch (1), fix me"
63 PropsJss fn1, PropsJss fn2 ->
67 PropsJss fn1, PropsJss fn2 ->
64 PropsJss \props -> do
68 PropsJss \props -> do
65 case fn1 props, fn2 props of
69 case fn1 props, fn2 props of
66 n1@(NestedJss _), n2@(NestedJss _) -> n1 <> n2
70 n1@(NestedJss _), n2@(NestedJss _) -> n1 <> n2
71+ p1@(PrimitiveJss _), p2@(PrimitiveJss _) -> p1 <> p2
67 x, y -> do
72 x, y -> do
68 let
73 let
69 _ = spy "x" x
74 _ = spy "x" x
70
75
71 _ = spy "y" y
76 _ = spy "y" y
72− unsafeCrashWith "Untreated branch second, fix me"
77+ unsafeCrashWith "Untreated branch (2), fix me"
73 x, y -> do
78 x, y -> do
74 let
79 let
75 _ = spy "x" x
80 _ = spy "x" x
76
81
77 _ = spy "y" y
82 _ = spy "y" y
78− unsafeCrashWith "Untreated branch second, fix me"
83+ unsafeCrashWith "Untreated branch (3), fix me"
79
84
80instance wfJSSElem ∷ WriteForeign (JSSElem props) where
85instance wfJSSElem ∷ WriteForeign (JSSElem props) where
81 writeImpl = case _ of
86 writeImpl = case _ of
@@ -117,6 +122,13 @@ instance jssAbleCss ∷ JSSAble p (StyleM Unit) where
117 rules = runS someCss
122 rules = runS someCss
118 ruleToObject = case _ of
123 ruleToObject = case _ of
119 Property (Key k) (Value v) -> Object.singleton (plain k) (jss (plain v))
124 Property (Key k) (Value v) -> Object.singleton (plain k) (jss (plain v))
125+ Nested (Sub (Selector (Refinement preds) (Elem el))) rules -> Object.singleton (el <> foldMap predicate preds) (jss (foldMap ruleToObject rules))
126+ Keyframe (Keyframes name frames) ->
127+ frames
128+ # foldMap \(Tuple pos rules) ->
129+ Object.singleton
130+ (show (round pos) <> "%")
131+ (NestedJss (foldMap ruleToObject rules))
120 x ->
132 x ->
121 unsafeCrashWith do
133 unsafeCrashWith do
122 let
134 let
components/src/Yoga/Monaco/Editor.purs+1−1
@@ -114,7 +114,7 @@ mkEditor = do
114 eddy <- monacoEditor
114 eddy <- monacoEditor
115 liftEffect $ modifyEditor (const (Just eddy))
115 liftEffect $ modifyEditor (const (Just eddy))
116 theme <- useTheme
116 theme <- useTheme
117− useEffect theme do
117+ useEffect theme.backgroundColour do
118 for_ maybeMonaco (initEditor theme)
118 for_ maybeMonaco (initEditor theme)
119 pure mempty
119 pure mempty
120 let
120 let
components/src/Yoga/SVG/Image.purs+2−1
@@ -3,6 +3,7 @@ module Yoga.SVG.Image where
3import Prelude
3import Prelude
4import Color (toHexString)
4import Color (toHexString)
5import Data.Array (elem, foldl, head, intercalate, snoc, uncons, zip, (:))
5import Data.Array (elem, foldl, head, intercalate, snoc, uncons, zip, (:))
6+import Data.Array.NonEmpty as NEA
6import Data.Int (round, toNumber)
7import Data.Int (round, toNumber)
7import Data.Maybe (Maybe(..), maybe)
8import Data.Maybe (Maybe(..), maybe)
8import Data.String (codePointFromChar)
9import Data.String (codePointFromChar)
@@ -45,7 +46,7 @@ mkLandingPageBackground = do
45 { fill: if theme.isLight then "url(#_Linear9)" else "url(#_Linear12)"
46 { fill: if theme.isLight then "url(#_Linear9)" else "url(#_Linear12)"
46 }
47 }
47 , screenText:
48 , screenText:
48− { fontFamily: theme.codeFontFamily
49+ { fontFamily: NEA.head theme.codeFontFamily
49 , fontSize: "0.85em"
50 , fontSize: "0.85em"
50 , fill: theme.textColour # toHexString
51 , fill: theme.textColour # toHexString
51 }
52 }
components/src/Yoga/Theme.purs+47−5
@@ -1,10 +1,10 @@
1module Yoga.Theme where
1module Yoga.Theme where
2
2
3import Prelude
3import Prelude
4−import CSS (contrast, darken, isLight, lighten, rotateHue)
4+import CSS (CSSVariable, Size, contrast, darken, isLight, lighten, reference, rotateHue, unitless, variable, (!*))
5+import CSS.Size (Calc, (!/))
5import Color (Color)
6import Color (Color)
6import Color as Color
7import Color as Color
7−import Data.Foldable (intercalate)
8import Data.Maybe (fromMaybe)
8import Data.Maybe (fromMaybe)
9import Data.Symbol (SProxy(..))
9import Data.Symbol (SProxy(..))
10import Record.Builder as RB
10import Record.Builder as RB
@@ -85,14 +85,56 @@ fromTheme theme =
85 (theme.altHighlightColour # darken 0.2)
85 (theme.altHighlightColour # darken 0.2)
86 -- fonts
86 -- fonts
87
87
88− >>> RB.modify (f ∷ _ "textFontFamily") (intercalate ",")
88+ -- >>> RB.modify (f ∷ _ "textFontFamily") (intercalate ",")
89+
89− >>> RB.modify (f ∷ _ "headingFontFamily") (intercalate ",")
90+ -- >>> RB.modify (f ∷ _ "headingFontFamily") (intercalate ",")
91+
90− >>> RB.modify (f ∷ _ "codeFontFamily") (intercalate ",")
92+ -- >>> RB.modify (f ∷ _ "codeFontFamily") (intercalate ",")
93+
91 >>> RB.insert (f ∷ _ "isLight") isLightTheme
94 >>> RB.insert (f ∷ _ "isLight") isLightTheme
95+ -- variables
96+
92 >>> RB.insert (f ∷ _ "fontWeightBold") "300"
97 >>> RB.insert (f ∷ _ "fontWeightBold") "300"
98+ >>> RB.insert (f ∷ _ "ratioVar") (ratio)
99+ >>> RB.insert (f ∷ _ "s0Var") (s0)
100+ >>> RB.modify (f ∷ _ "s0") (const $ reference s0)
101+ >>> RB.modify (f ∷ _ "ratio") (const $ reference ratio)
102+ >>> RB.insert (f ∷ _ "s1Var") s1
103+ >>> RB.insert (f ∷ _ "s2Var") s2
104+ >>> RB.insert (f ∷ _ "s3Var") s3
105+ >>> RB.insert (f ∷ _ "s4Var") s4
106+ >>> RB.insert (f ∷ _ "s5Var") s5
107+ >>> RB.insert (f ∷ _ "s_1Var") s_1
108+ >>> RB.insert (f ∷ _ "s_2Var") s_2
109+ >>> RB.insert (f ∷ _ "s_3Var") s_3
110+ >>> RB.insert (f ∷ _ "s_4Var") s_4
111+ >>> RB.insert (f ∷ _ "s_5Var") s_5
112+ >>> RB.insert (f ∷ _ "s1") (reference s1)
113+ >>> RB.insert (f ∷ _ "s2") (reference s2)
114+ >>> RB.insert (f ∷ _ "s3") (reference s3)
115+ >>> RB.insert (f ∷ _ "s4") (reference s4)
116+ >>> RB.insert (f ∷ _ "s5") (reference s5)
117+ >>> RB.insert (f ∷ _ "s_1") (reference s_1)
118+ >>> RB.insert (f ∷ _ "s_2") (reference s_2)
119+ >>> RB.insert (f ∷ _ "s_3") (reference s_3)
120+ >>> RB.insert (f ∷ _ "s_4") (reference s_4)
121+ >>> RB.insert (f ∷ _ "s_5") (reference s_5)
93 )
122 )
94 theme
123 theme
95 where
124 where
125+ ratio ∷ CSSVariable (Size Calc)
126+ ratio = variable "ratio" (unitless theme.ratio !* unitless 1.0)
127+ s5 = variable "s5" (reference s4 !* reference ratio)
128+ s4 = variable "s4" (reference s3 !* reference ratio)
129+ s3 = variable "s3" (reference s2 !* reference ratio)
130+ s2 = variable "s2" (reference s1 !* reference ratio)
131+ s1 = variable "s1" (reference s0 !* reference ratio)
132+ s0 = variable "s0" (theme.s0)
133+ s_1 = variable "s-1" (reference s0 !/ reference ratio)
134+ s_2 = variable "s-2" (reference s_1 !/ reference ratio)
135+ s_3 = variable "s-3" (reference s_2 !/ reference ratio)
136+ s_4 = variable "s-4" (reference s_3 !/ reference ratio)
137+ s_5 = variable "s-5" (reference s_4 !/ reference ratio)
96 isLightTheme = isLight theme.backgroundColour
138 isLightTheme = isLight theme.backgroundColour
97 lighter ∷ Color -> Color
139 lighter ∷ Color -> Color
98 lighter = if isLightTheme then lighten 0.04 else lighten 0.02
140 lighter = if isLightTheme then lighten 0.04 else lighten 0.02
components/src/Yoga/Theme/CSSBaseline.purs+26−19
@@ -1,7 +1,9 @@
1module Yoga.Theme.CSSBaseline where
1module Yoga.Theme.CSSBaseline where
2
2
3import Prelude hiding (add)
3import Prelude hiding (add)
4+import CSS (declare)
4import Color (toHexString)
5import Color (toHexString)
6+import Data.Array.NonEmpty as NEA
5import Effect (Effect)
7import Effect (Effect)
6import JSS (JSSClasses, JSSElem, jss, jssClasses)
8import JSS (JSSClasses, JSSElem, jss, jssClasses)
7import React.Basic (ReactComponent)
9import React.Basic (ReactComponent)
@@ -10,7 +12,7 @@ import React.Basic.Hooks as React
10import Yoga.Font.Rubik as Rubik
12import Yoga.Font.Rubik as Rubik
11import Yoga.Font.VictorMono as VictorMono
13import Yoga.Font.VictorMono as VictorMono
12import Yoga.Theme.Styles (makeStylesJSS)
14import Yoga.Theme.Styles (makeStylesJSS)
13−import Yoga.Theme.Types (YogaTheme)
15+import Yoga.Theme.Types (YogaTheme, CSSTheme)
14
16
15mkCssBaseline ∷
17mkCssBaseline ∷
16 Effect (ReactComponent { kids ∷ Array JSX })
18 Effect (ReactComponent { kids ∷ Array JSX })
@@ -29,22 +31,21 @@ html =
29 , boxSizing: "border-box"
31 , boxSizing: "border-box"
30 }
32 }
31
33
32−root ∷ JSSElem {}
34+root ∷ CSSTheme -> JSSElem {}
33−root =
35+root theme =
34− jss
36+ jss do
35− { "--ratio": "1.5"
37+ declare theme.ratioVar
36− , "--s-5": "calc(var(--s-4) / var(--ratio))"
38+ declare theme.s_5Var
37− , "--s-4": "calc(var(--s-3) / var(--ratio))"
39+ declare theme.s_4Var
38− , "--s-3": "calc(var(--s-2) / var(--ratio))"
40+ declare theme.s_3Var
39− , "--s-2": "calc(var(--s-1) / var(--ratio))"
41+ declare theme.s_2Var
40− , "--s-1": "calc(var(--s0) / var(--ratio))"
42+ declare theme.s_1Var
41− , "--s0": "1rem"
43+ declare theme.s0Var
42− , "--s1": "calc(var(--s0) * var(--ratio))"
44+ declare theme.s1Var
43− , "--s2": "calc(var(--s1) * var(--ratio))"
45+ declare theme.s2Var
44− , "--s3": "calc(var(--s2) * var(--ratio))"
46+ declare theme.s3Var
45− , "--s4": "calc(var(--s3) * var(--ratio))"
47+ declare theme.s4Var
46− , "--s5": "calc(var(--s4) * var(--ratio))"
48+ declare theme.s5Var
47− }
48
49
49styles ∷ JSSClasses YogaTheme {} ( "@global" ∷ JSSElem {} )
50styles ∷ JSSClasses YogaTheme {} ( "@global" ∷ JSSElem {} )
50styles =
51styles =
@@ -53,7 +54,7 @@ styles =
53 jss
54 jss
54 { html
55 { html
55 , "@font-face": jss (Rubik.fontFamilies <> VictorMono.fontFamilies)
56 , "@font-face": jss (Rubik.fontFamilies <> VictorMono.fontFamilies)
56− , ":root": root
57+ , ":root": root theme
57 , "*":
58 , "*":
58 { maxWidth: theme.measure
59 { maxWidth: theme.measure
59 }
60 }
@@ -73,7 +74,7 @@ styles =
73 { margin: 0
74 { margin: 0
74 , backgroundColor: theme.backgroundColour # toHexString
75 , backgroundColor: theme.backgroundColour # toHexString
75 , color: theme.textColour # toHexString
76 , color: theme.textColour # toHexString
76− , fontFamily: theme.textFontFamily
77+ , fontFamily: NEA.head theme.textFontFamily
77 , "&::backdrop":
78 , "&::backdrop":
78 { backgroundColor: theme.backgroundColour # toHexString
79 { backgroundColor: theme.backgroundColour # toHexString
79 }
80 }
@@ -98,5 +99,11 @@ styles =
98 { "font-size": "var(--s1)"
99 { "font-size": "var(--s1)"
99 , "text-transform": "uppercase"
100 , "text-transform": "uppercase"
100 }
101 }
102+ , "code, pre":
103+ { fontFamily: NEA.head theme.codeFontFamily
104+ , lineHeight: "var(--ratio)"
105+ , fontSize: "var(--s0)"
106+ , fontSmooth: "never"
107+ }
101 }
108 }
102 }
109 }
components/src/Yoga/Theme/Default.purs+4−1
@@ -1,6 +1,7 @@
1module Yoga.Theme.Default where
1module Yoga.Theme.Default where
2
2
3import Prelude
3import Prelude
4+import CSS (rem)
4import Color as Color
5import Color as Color
5import Data.Array.NonEmpty (cons')
6import Data.Array.NonEmpty (cons')
6import Data.Maybe (fromMaybe')
7import Data.Maybe (fromMaybe')
@@ -23,7 +24,7 @@ darkTheme =
23 , altHighlightColour: Color.hsl 84.0 0.617 0.631
24 , altHighlightColour: Color.hsl 84.0 0.617 0.631
24 , textFontFamily: cons' "Rubik" systemFontStack
25 , textFontFamily: cons' "Rubik" systemFontStack
25 , headingFontFamily: cons' "Rubik" systemFontStack
26 , headingFontFamily: cons' "Rubik" systemFontStack
26− , codeFontFamily: cons' "'VictorMono'" [ "monospace" ]
27+ , codeFontFamily: cons' "VictorMono" []
27 , yellow: Color.rgb 255 235 149
28 , yellow: Color.rgb 255 235 149
28 , green: Color.hsl 84.0 0.617 0.631
29 , green: Color.hsl 84.0 0.617 0.631
29 , pink: Color.hsl 276.0 0.677 0.745
30 , pink: Color.hsl 276.0 0.677 0.745
@@ -35,6 +36,8 @@ darkTheme =
35 , white: Color.rgb 250 250 250
36 , white: Color.rgb 250 250 250
36 , measure: "60ch"
37 , measure: "60ch"
37 , borderThin: "0.125rem"
38 , borderThin: "0.125rem"
39+ , ratio: 1.5
40+ , s0: 1.0 # rem
38 }
41 }
39
42
40lightTheme ∷ Theme
43lightTheme ∷ Theme
components/src/Yoga/Theme/Types.purs+31−3
@@ -1,5 +1,7 @@
1module Yoga.Theme.Types where
1module Yoga.Theme.Types where
2
2
3+import CSS (CSSVariable, Rel, Size)
4+import CSS.Size (Calc)
3import Color (Color)
5import Color (Color)
4import Data.Array.NonEmpty (NonEmptyArray)
6import Data.Array.NonEmpty (NonEmptyArray)
5
7
@@ -23,6 +25,8 @@ type Theme
23 , grey ∷ Color
25 , grey ∷ Color
24 , measure ∷ String
26 , measure ∷ String
25 , borderThin ∷ String
27 , borderThin ∷ String
28+ , ratio ∷ Number
29+ , s0 ∷ Size Rel
26 }
30 }
27
31
28type YogaTheme
32type YogaTheme
@@ -48,9 +52,9 @@ type YogaTheme
48 , altHighlightColour ∷ Color
52 , altHighlightColour ∷ Color
49 , altHighlightColourDark ∷ Color
53 , altHighlightColourDark ∷ Color
50 , isLight ∷ Boolean
54 , isLight ∷ Boolean
51− , textFontFamily ∷ String
55+ , textFontFamily ∷ NonEmptyArray String
52− , headingFontFamily ∷ String
56+ , headingFontFamily ∷ NonEmptyArray String
53− , codeFontFamily ∷ String
57+ , codeFontFamily ∷ NonEmptyArray String
54 , yellow ∷ Color
58 , yellow ∷ Color
55 , green ∷ Color
59 , green ∷ Color
56 , pink ∷ Color
60 , pink ∷ Color
@@ -63,6 +67,30 @@ type YogaTheme
63 , fontWeightBold ∷ String
67 , fontWeightBold ∷ String
64 , measure ∷ String
68 , measure ∷ String
65 , borderThin ∷ String
69 , borderThin ∷ String
70+ , ratioVar ∷ CSSVariable (Size Calc)
71+ , s_5Var ∷ CSSVariable (Size Calc)
72+ , s_4Var ∷ CSSVariable (Size Calc)
73+ , s_3Var ∷ CSSVariable (Size Calc)
74+ , s_2Var ∷ CSSVariable (Size Calc)
75+ , s_1Var ∷ CSSVariable (Size Calc)
76+ , s0Var ∷ CSSVariable (Size Rel)
77+ , s1Var ∷ CSSVariable (Size Calc)
78+ , s2Var ∷ CSSVariable (Size Calc)
79+ , s3Var ∷ CSSVariable (Size Calc)
80+ , s4Var ∷ CSSVariable (Size Calc)
81+ , s5Var ∷ CSSVariable (Size Calc)
82+ , s0 ∷ Size Rel
83+ , ratio ∷ Size Calc
84+ , s_5 ∷ Size Calc
85+ , s_4 ∷ Size Calc
86+ , s_3 ∷ Size Calc
87+ , s_2 ∷ Size Calc
88+ , s_1 ∷ Size Calc
89+ , s1 ∷ Size Calc
90+ , s2 ∷ Size Calc
91+ , s3 ∷ Size Calc
92+ , s4 ∷ Size Calc
93+ , s5 ∷ Size Calc
66 )
94 )
67
95
68type CSSTheme
96type CSSTheme
components/src/Yoga/Typography/Header.purs+4−3
@@ -3,6 +3,7 @@ module Yoga.Typography.Header where
3import Prelude
3import Prelude
4import Color (toHexString)
4import Color (toHexString)
5import Data.Array as Array
5import Data.Array as Array
6+import Data.Array.NonEmpty as NEA
6import Data.Foldable (intercalate)
7import Data.Foldable (intercalate)
7import Data.Maybe (Maybe)
8import Data.Maybe (Maybe)
8import Effect (Effect)
9import Effect (Effect)
@@ -28,7 +29,7 @@ mkH = do
28 $ jssClasses \(theme ∷ CSSTheme) ->
29 $ jssClasses \(theme ∷ CSSTheme) ->
29 { common:
30 { common:
30 { color: theme.textColour # toHexString
31 { color: theme.textColour # toHexString
31− , fontFamily: theme.headingFontFamily
32+ , fontFamily: NEA.head theme.headingFontFamily
32 }
33 }
33 , h1:
34 , h1:
34 { textTransform: "uppercase"
35 { textTransform: "uppercase"
@@ -45,8 +46,8 @@ mkH = do
45 , padding: 0
46 , padding: 0
46 }
47 }
47 , h3:
48 , h3:
48− { -- fontSize: "2.2em"
49+ { fontSize: "2.2em"
49− margin: 0
50+ , margin: 0
50 , padding: 0
51 , padding: 0
51 }
52 }
52 , h4:
53 , h4:
components/src/Yoga/Typography/Paragraph.purs−1
@@ -17,7 +17,6 @@ mkP = do
17 $ jssClasses \(theme ∷ CSSTheme) ->
17 $ jssClasses \(theme ∷ CSSTheme) ->
18 { p:
18 { p:
19 { color: theme.textColour # toHexString
19 { color: theme.textColour # toHexString
20− , fontFamily: theme.textFontFamily
21 , fontSize: "1em"
20 , fontSize: "1em"
22 , margin: "0.67em 0 0.33em 0"
21 , margin: "0.67em 0 0.33em 0"
23 , padding: "0.67em 0 0.33em 0"
22 , padding: "0.67em 0 0.33em 0"
server/package-lock.json+3−4
@@ -945,10 +945,9 @@
945 }
945 }
946 },
946 },
947 "minimist": {
947 "minimist": {
948− "version": "1.2.0",
948+ "version": "1.2.5",
949− "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
949+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
950− "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
950+ "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
951− "dev": true
952 },
951 },
953 "minipass": {
952 "minipass": {
954 "version": "2.9.0",
953 "version": "2.9.0",
server/package.json+2−1
@@ -17,7 +17,8 @@
17 "express": "^4.17.1",
17 "express": "^4.17.1",
18 "fs-extra": "^9.0.0",
18 "fs-extra": "^9.0.0",
19 "json-parser": "^3.1.2",
19 "json-parser": "^3.1.2",
20− "uuid": "^7.0.2"
20+ "uuid": "^7.0.2",
21+ "minimist": "^1.2.2"
21 },
22 },
22 "devDependencies": {
23 "devDependencies": {
23 "purescript": "^0.13.6",
24 "purescript": "^0.13.6",