git.iko.soy/rowtype-yoga/psfp
on afa9355 help sign in
186 lines 7.3 kB history raw
1module PSLayout where
3import Prelude
4import Color as Color
5import Data.Maybe (Maybe(..), fromMaybe)
6import Data.Tuple.Nested ((/\))
7import Effect (Effect)
8import MDX (MDX)
9import MDXProvider (MdxProviderProps)
10import Milkis.Impl (FetchImpl)
11import React.Basic (ReactComponent)
12import React.Basic.DOM as R
13import React.Basic.Emotion as Emotion
14import React.Basic.Hooks (ReactChildren, element, reactComponentWithChildren, useState')
15import React.Basic.Hooks as React
16import Yoga ((/>), (</), (</*))
17import Yoga as Y
18import Yoga.Block as Block
19import Yoga.Block.Atom.Toggle.Types (TogglePosition(..))
20import Yoga.Block.Container as Container
21import Yoga.Block.Container.Style (DarkOrLightMode(..), colour)
22import Yoga.Block.Icon.SVG as Icon
23import Yoga.Block.Internal (_0)
24import Yoga.Block.Modal as Modal
26type SiteQueryResult =
27 { siteMetadata ∷
28 { title ∷ String
29 , menuLinks ∷ Array { name ∷ String, link ∷ String }
30 }
31 }
33data ShowModal
34 = ShowModal Modal.Props
35 | HideModal
37mkLayout ∷
38 FetchImpl ->
39 Effect
40 ( ReactComponent
41 { children ∷ ReactChildren MDX
42 , siteInfo ∷ SiteQueryResult
43 , mdxProviderComponent ∷ ReactComponent MdxProviderProps
44 }
45 )
46mkLayout fetchImpl = do
47 reactComponentWithChildren "MDXLayout" \{ children, siteInfo, mdxProviderComponent } -> React.do
48 darkOrLightMode /\ setDarkOrLightMode <- useState' Nothing
49 togglePosition /\ setTogglePosition <- useState' ToggleIsLeft
50 let
51 themeToMaybeTogglePosition =
52 darkOrLightMode
53 <#> case _ of
54 DarkMode -> ToggleIsRight
55 LightMode -> ToggleIsLeft
56 darkThemeToggle =
57 Block.toggle
58 Y.</> do
59 { className: "dark-light-toggle"
60 , css:
61 Emotion.css
62 { marginRight: Emotion.str "0"
63 , marginLeft: Emotion.str "auto"
64 }
65 , setTogglePosition:
66 case _ of
67 ToggleIsLeft -> setDarkOrLightMode (Just LightMode)
68 ToggleIsRight -> setDarkOrLightMode (Just DarkMode)
69 , togglePosition: themeToMaybeTogglePosition # fromMaybe togglePosition
70 , left:
71 Block.icon
72 Y.</> do
73 { icon: Icon.moon
74 , stroke: Emotion.str "#eef"
75 }
76 , right:
77 Block.icon
78 Y.</> do
79 { icon: Icon.sun
80 , stroke: Emotion.str "yellow"
81 }
82 , backgroundLeft:
83 Color.hsl 205.0 1.0 0.80
84 , backgroundRight:
85 Color.hsl 250.0 1.0 0.1
86 , ariaLabel: "Use dark mode"
87 }
88 header =
89 Block.box
90 </ { className: "top-box"
91 , css:
92 Emotion.css
93 { background: Emotion.str colour.background
94 }
95 }
96 /> [ Block.cluster
97 </* { justify: "space-between"
98 , className: "header"
99 , space: "var(--s-2)"
100 , css: Emotion.css { width: Emotion.percent 100.0 }
101 }
102 /> do
103 [ Y.styled
104 R.span'
105 { className: "blog-header"
106 , css:
107 Emotion.css
108 { fontSize: Emotion.str "min(var(--s3), calc(var(--s1) + 1vw))"
109 , textTransform: Emotion.str "uppercase"
110 , letterSpacing: Emotion.str "calc(min(var(--s0) + 3vw), var(--s2) * -1.7)"
111 , fontWeight: Emotion.str "300"
112 , color: Emotion.str colour.text
113 }
114 }
115 [ R.text siteInfo.siteMetadata.title ]
116 , darkThemeToggle
117 ]
118 ]
119 pure
120 $ element Container.component
121 { themeVariant: darkOrLightMode
122 , onPreferredSystemThemeChange:
123 case _ of
124 LightMode -> setTogglePosition ToggleIsLeft
125 DarkMode -> setTogglePosition ToggleIsRight
126 , content:
127 Y.styled Block.stack
128 { className: "blog-content"
129 , space: _0
130 , splitAfter: 2
131 , css:
132 Emotion.css
133 { minHeight: Emotion.vh 100.0
134 , background: Emotion.str colour.background
135 , borderRadius: Emotion.str "0 var(--s1) var(--s1) 0"
136 }
137 }
138 [ header
139 , Block.centre
140 </* { className: "centre"
141 , padding: _0
142 , gutters: _0
143 , css:
144 Emotion.css
145 { maxWidth: Emotion.ch 90.0
146 , fontSize: Emotion.str "calc( min( (var(--s-1) * 1.7) + 0.7vw , var(--s0)*1.1 ) )"
147 }
148 }
149 /> [ Block.box
150 </ do
151 { padding: Emotion.px 16
152 , css:
153 Emotion.css
154 { "& > p:first-of-type":
155 Emotion.nested
156 $ Emotion.css
157 { minHeight: Emotion.str "min(calc(var(--s-1) + 2px + 3vw), var(--s3))"
158 , "&:first-letter":
159 Emotion.nested
160 $ Emotion.css
161 { overflow: Emotion.str "visible"
162 , display: Emotion.inlineBlock
163 , float: Emotion.str "left"
164 , fontSize: Emotion.str "min(calc(var(--s0) * 1 + 8.03vw), var(--s5))"
165 , fontFamily: Emotion.str "Cormorant Garamond"
166 , lineHeight: Emotion.str "min(calc(var(--s-1) + 2px + 3vw), var(--s3))"
167 , marginTop: Emotion.str "min(calc(var(--s-1) + 1.5vw), var(--s2))"
168 , marginRight: Emotion.var "--s-2"
169 }
170 }
171 }
172 }
173 /> [ element mdxProviderComponent { children } ]
174 ]
175 , Y.styled Block.box
176 { className: "blog-footer"
177 , css:
178 Emotion.css
179 { background: Emotion.str colour.backgroundLayer1
180 , borderTop: Emotion.str $ "1px solid " <> colour.backgroundLayer3
181 , color: Emotion.str colour.text
182 }
183 }
184 [ R.text "Mark Eibes" ]
185 ]
186 }