@@ -1,10 +1,7 @@
1module Yoga.SVG.Image where
1module Yoga.SVG.Image where
3import Prelude
3import Prelude
5−import Color (toHexString)
6import Data.Array (elem, foldl, head, intercalate, snoc, uncons, zip, (:))
4import Data.Array (elem, foldl, head, intercalate, snoc, uncons, zip, (:))
7−import Data.Array.NonEmpty as NEA
8import Data.Int (round, toNumber)
5import Data.Int (round, toNumber)
9import Data.Maybe (Maybe(..), maybe)
6import Data.Maybe (Maybe(..), maybe)
10import Data.String (codePointFromChar)
7import Data.String (codePointFromChar)
@@ -12,114 +9,136 @@ import Data.String as String
12import Data.Tuple.Nested ((/\))
9import Data.Tuple.Nested ((/\))
13import Effect (Effect)
10import Effect (Effect)
14import Effect.Unsafe (unsafePerformEffect)
11import Effect.Unsafe (unsafePerformEffect)
15−import JSS (jssClasses)
16import Random.PseudoRandom (mkSeed, randomRs)
12import Random.PseudoRandom (mkSeed, randomRs)
17import React.Basic (JSX, element)
13import React.Basic (JSX, element)
18import React.Basic.DOM (unsafeCreateDOMComponent)
14import React.Basic.DOM (unsafeCreateDOMComponent)
19import React.Basic.DOM as HTML
15import React.Basic.DOM as HTML
20import React.Basic.DOM.SVG as SVG
16import React.Basic.DOM.SVG as SVG
17+import React.Basic.Emotion as E
21import React.Basic.Hooks (ReactComponent)
18import React.Basic.Hooks (ReactComponent)
22import React.Basic.Hooks as React
19import React.Basic.Hooks as React
20+import Yoga.Block.Container.Style (colour)
23import Yoga.DOM.Hook (useBoundingBox)
21import Yoga.DOM.Hook (useBoundingBox)
24import Yoga.SVG.Icon (Raw)
22import Yoga.SVG.Icon (Raw)
25import Yoga.Scroll.Hook (useScrollYPosition)
23import Yoga.Scroll.Hook (useScrollYPosition)
26−import Yoga.Theme.Styles (makeStylesJSS, useTheme)
27−import Yoga.Theme.Types (CSSTheme)
29foreign import landingPageDarkRaw ∷ ∀ r. Raw r
25foreign import landingPageDarkRaw ∷ ∀ r. Raw r
31foreign import landingPageLightRaw ∷ ∀ r. Raw r
27foreign import landingPageLightRaw ∷ ∀ r. Raw r
30+ E.keyframes -- [TODO] how?
31+ { "0%": E.css { opacity: E.str "0.0" }
32+ , "50%": E.css { opacity: E.str "1.0" }
37+ { "0%": E.css { transform: E.str "translate3d(-140%, 4%, 0)" }
38+ , "100%": E.css { transform: E.str "translate3d(70%, -4%, 0)" }
43+ { "0%": E.css { transform: E.str "translate3d(-10%, 0%, 0)" }
44+ , "100%": E.css { transform: E.str "translate3d(10%, 0%, 0)" }
49+ { "0%": E.css { fill: E.str "rgba(250, 250, 250, 0.2)" }
50+ , "50%": E.css { fill: E.str "rgba(250, 250, 250, 0.7)" }
51+ , "70%": E.css { fill: E.str "rgba(250, 250, 250, 0.4)" }
52+ , "100%": E.css { fill: E.str "rgba(250, 250, 250, 1.0)" }
57+ { "0%": E.css { fill: E.str "rgba(250, 250, 250, 0.7)" }
58+ , "100%": E.css { fill: E.str "rgba(250, 250, 250, 0.78)" }
63+ { "0%": E.css { transform: E.str "rotate(0deg) scale(1,1)" }
64+ , "100%": E.css { transform: E.str "rotate(1deg) scale(1.01, 1.01)" }
70+ { fill: E.str colour.background
74+ { cx: E.str if theme.isLight then "721" else "175"
75+ , cy: E.str if theme.isLight then "355" else "310"
76+ , rx: E.str if theme.isLight then "647" else "330"
77+ , ry: E.str if theme.isLight then "310" else "252"
81+ { fill: E.str if theme.isLight then "url(#_Linear9)" else "url(#_Linear12)"
85+ { fontFamily: E.var "--font-mono"
86+ , fontSize: E.str "0.85em"
87+ , fill: E.str colour.text
89+ , keyword: E.css { fill: E.str "green" }
90+ , typeName: E.css { fill: E.str "rebeccapurple" }
93+ { animation: E.str "$animatedCursor 0.5s linear infinite"
94+ , animationDirection: E.str "alternate"
98+ { animation: E.str "$movingCloud1 200s linear infinite"
99+ , animationDelay: E.str "-150s"
103+ { animation: E.str "$movingCloud2 120s linear infinite"
104+ , animationDirection: E.str "alternate"
108+ { animation: E.str "$movingCloud2 120s linear infinite"
109+ , animationDelay: E.str "-120s"
110+ , animationDirection: E.str "alternate"
114+ { animation: E.str "$twinkleFast 0.2s ease-in-out infinite"
115+ , animationDirection: E.str "alternate"
119+ { animation: E.str "$twinkle 8s ease-in-out infinite"
120+ , animationDelay: E.str "4s"
121+ , animationDirection: E.str "alternate"
125+ { animation: E.str "$twinkle 4s ease-in-out infinite"
126+ , animationDelay: E.str "3s"
127+ , animationDirection: E.str "alternate"
131+ { animation: E.str "$rotateStars 30s linear infinite"
132+ , transformOrigin: E.str "top center"
133+ , animationDirection: E.str "alternate"
33mkLandingPageBackground ∷ Effect (ReactComponent { className ∷ String })
137mkLandingPageBackground ∷ Effect (ReactComponent { className ∷ String })
34mkLandingPageBackground = do
138mkLandingPageBackground = do
37− $ jssClasses \(theme ∷ CSSTheme) ->
39− { fill: theme.backgroundColour # toHexString
42− { cx: if theme.isLight then "721" else "175"
43− , cy: if theme.isLight then "355" else "310"
44− , rx: if theme.isLight then "647" else "330"
45− , ry: if theme.isLight then "310" else "252"
48− { fill: if theme.isLight then "url(#_Linear9)" else "url(#_Linear12)"
51− { fontFamily: NEA.head theme.codeFontFamily
53− , fill: theme.textColour # toHexString
55− , keyword: { fill: theme.green # toHexString }
56− , typeName: { fill: theme.purple # toHexString }
57− , "@keyframes animatedCursor":
58− { "0%": { opacity: "0.0" }
59− , "50%": { opacity: "1.0" }
62− { animation: "$animatedCursor 0.5s linear infinite"
63− , animationDirection: "alternate"
65− , "@keyframes movingCloud1":
66− { "0%": { transform: "translate3d(-140%, 4%, 0)" }
67− , "100%": { transform: "translate3d(70%, -4%, 0)" }
70− { animation: "$movingCloud1 200s linear infinite"
71− , animationDelay: "-150s"
73− , "@keyframes movingCloud2":
74− { "0%": { transform: "translate3d(-10%, 0%, 0)" }
75− , "100%": { transform: "translate3d(10%, 0%, 0)" }
78− { animation: "$movingCloud2 120s linear infinite"
79− , animationDirection: "alternate"
82− { animation: "$movingCloud2 120s linear infinite"
83− , animationDelay: "-120s"
84− , animationDirection: "alternate"
86− , "@keyframes twinkle":
87− { "0%": { fill: "rgba(250, 250, 250, 0.2)" }
88− , "50%": { fill: "rgba(250, 250, 250, 0.7)" }
89− , "70%": { fill: "rgba(250, 250, 250, 0.4)" }
90− , "100%": { fill: "rgba(250, 250, 250, 1.0)" }
92− , "@keyframes twinkleFast":
93− { "0%": { fill: "rgba(250, 250, 250, 0.7)" }
94− , "100%": { fill: "rgba(250, 250, 250, 0.78)" }
97− { animation: "$twinkleFast 0.2s ease-in-out infinite"
98− , animationDirection: "alternate"
101− { animation: "$twinkle 8s ease-in-out infinite"
102− , animationDelay: "4s"
103− , animationDirection: "alternate"
106− { animation: "$twinkle 4s ease-in-out infinite"
107− , animationDelay: "3s"
108− , animationDirection: "alternate"
110− , "@keyframes rotateStars":
111− { "0%": { transform: "rotate(0deg) scale(1,1)" }
112− , "100%": { transform: "rotate(1deg) scale(1.01, 1.01)" }
115− { animation: "$rotateStars 30s linear infinite"
116− , transformOrigin: "top center"
117− , animationDirection: "alternate"
120 React.reactComponent "LandingPageBackground" \{ className } -> React.do
139 React.reactComponent "LandingPageBackground" \{ className } -> React.do
121− theme <- useTheme
140+ let theme = { isLight: true } -- [TODO]
122− classes <- useStyles {}
141+ let classes = mkClasses theme
123 scrollY <- useScrollYPosition
142 scrollY <- useScrollYPosition
124 bb /\ ref <- useBoundingBox
143 bb /\ ref <- useBoundingBox
@@ -157,37 +176,42 @@ mkLandingPageBackground = do
157 { d: "M800.828 448.051V-3.513H-3.028v451.564h803.856z"
176 { d: "M800.828 448.051V-3.513H-3.028v451.564h803.856z"
158 , fill: "url(#_Linear2)"
177 , fill: "url(#_Linear2)"
160− , SVG.ellipse
179+ , E.element SVG.ellipse'
180+ { className: "light-ellipsis"
161− { className: classes.lightEllipsis
181+ , css: classes.lightEllipsis
162 , fill: "url(#_Radial3)"
182 , fill: "url(#_Radial3)"
164 , stars classes.stars classes
184 , stars classes.stars classes
165 -- bgcloud
185 -- bgcloud
166− , SVG.path
186+ , E.element SVG.path'
167 { d: "M610.291 177.316c-35.879-.428-84.67-.691-138.392-.689-38.684.002-74.811.141-105.402.38-49.14-2.745-80.877-9.954-80.877-14.718 0-1.333 2.655.335 7.294-.896 96.772-.175 171.302-1.213 171.302-2.464 0-1.107-59.462-3.372-140.106-3.687 38.487-2.059 102.543-4.972 173.823-4.972 11.996 0 23.761.07 35.216.206 20.76-4.638 60.945-2.784 107.07-2.784 36.08 0 68.525-.075 90.882 2.983 32.491.899 72.142-1.186 114.922-.379 38.68.729 74.805 1.273 105.395 1.613 49.101 3.673 80.599 8.516 80.54 13.279-.016 1.334-2.504 2.58-7.158 3.723-96.763-1.654-171.297-2.024-171.312-.774-.013 1.108 58.473 3.15 139.105 4.989-38.514 3.085-101.653 4.38-172.925 3.033-11.995-.227-23.757-.52-35.209-.872-20.815 4.245-61.034 6.631-107.154 5.759-24.754-.468-47.786-1.809-67.014-3.73z"
187 { d: "M610.291 177.316c-35.879-.428-84.67-.691-138.392-.689-38.684.002-74.811.141-105.402.38-49.14-2.745-80.877-9.954-80.877-14.718 0-1.333 2.655.335 7.294-.896 96.772-.175 171.302-1.213 171.302-2.464 0-1.107-59.462-3.372-140.106-3.687 38.487-2.059 102.543-4.972 173.823-4.972 11.996 0 23.761.07 35.216.206 20.76-4.638 60.945-2.784 107.07-2.784 36.08 0 68.525-.075 90.882 2.983 32.491.899 72.142-1.186 114.922-.379 38.68.729 74.805 1.273 105.395 1.613 49.101 3.673 80.599 8.516 80.54 13.279-.016 1.334-2.504 2.58-7.158 3.723-96.763-1.654-171.297-2.024-171.312-.774-.013 1.108 58.473 3.15 139.105 4.989-38.514 3.085-101.653 4.38-172.925 3.033-11.995-.227-23.757-.52-35.209-.872-20.815 4.245-61.034 6.631-107.154 5.759-24.754-.468-47.786-1.809-67.014-3.73z"
168 , fill: if theme.isLight then "#ddf0fb" else "#240c3c"
188 , fill: if theme.isLight then "#ddf0fb" else "#240c3c"
169− , className: classes.movingCloud1
189+ , css: classes.movingCloud1
190+ , className: "moving-cloud-1"
170 , transform: "translate(0 " <> show (scrolled * 20.0) <> ")"
191 , transform: "translate(0 " <> show (scrolled * 20.0) <> ")"
172 -- bgcloud
193 -- bgcloud
173− , SVG.path
194+ , E.element SVG.path'
174 { d: "M609.299 171.607c-35.88-.338-84.67-.545-138.392-.543-38.684.001-74.812.111-105.402.299-49.141-2.166-80.694-5.519-80.694-9.279 0-1.052 2.472-2.073 7.111-3.045 96.772-.137 171.302-.957 171.302-1.944-.001-.874-58.506-1.614-139.15-1.862 38.471-3.009 101.587-4.973 172.867-4.973 11.996 0 23.761.055 35.216.162 20.76-3.66 60.945-6.143 107.07-6.143 36.08 0 68.525 1.519 90.882 3.933 32.491.709 72.142 1.432 114.922 2.069 38.68.575 74.805 1.005 105.395 1.272 49.101 2.9 80.598 6.722 80.54 10.482-.017 1.052-2.505 2.036-7.158 2.938-96.763-1.305-171.297-1.597-171.312-.611-.014.875 58.473 2.486 139.104 3.938-38.514 2.435-101.653 3.457-172.924 2.394a3771.84 3771.84 0 01-35.21-.688c-20.814 3.35-61.033 5.234-107.153 4.545-24.754-.369-47.786-1.428-67.014-2.944z"
195 { d: "M609.299 171.607c-35.88-.338-84.67-.545-138.392-.543-38.684.001-74.812.111-105.402.299-49.141-2.166-80.694-5.519-80.694-9.279 0-1.052 2.472-2.073 7.111-3.045 96.772-.137 171.302-.957 171.302-1.944-.001-.874-58.506-1.614-139.15-1.862 38.471-3.009 101.587-4.973 172.867-4.973 11.996 0 23.761.055 35.216.162 20.76-3.66 60.945-6.143 107.07-6.143 36.08 0 68.525 1.519 90.882 3.933 32.491.709 72.142 1.432 114.922 2.069 38.68.575 74.805 1.005 105.395 1.272 49.101 2.9 80.598 6.722 80.54 10.482-.017 1.052-2.505 2.036-7.158 2.938-96.763-1.305-171.297-1.597-171.312-.611-.014.875 58.473 2.486 139.104 3.938-38.514 2.435-101.653 3.457-172.924 2.394a3771.84 3771.84 0 01-35.21-.688c-20.814 3.35-61.033 5.234-107.153 4.545-24.754-.369-47.786-1.428-67.014-2.944z"
175 , fill: if theme.isLight then "#d8effd" else "#120b38"
196 , fill: if theme.isLight then "#d8effd" else "#120b38"
176− , className: classes.movingCloud1
197+ , css: classes.movingCloud1
198+ , className: "moving-cloud-1"
177 , transform: "translate(0 " <> show (scrolled * 20.0) <> ")"
199 , transform: "translate(0 " <> show (scrolled * 20.0) <> ")"
179 -- rightcloud
201 -- rightcloud
180− , SVG.path
202+ , E.element SVG.path'
181 { d: "M684.234 222.269c-12.108-1.642-29.721-2.832-29.76-5.218-.063-3.861 34.226-4.225 76.6-3.504 42.375.721 75.9-2.707 76.956 1.008 2.476 8.704-12.549 8.552-32.56 10.141-12.403-.58-28.24.216-44.434.479-16.193.263-35.197-1.331-46.802-2.906z"
203 { d: "M684.234 222.269c-12.108-1.642-29.721-2.832-29.76-5.218-.063-3.861 34.226-4.225 76.6-3.504 42.375.721 75.9-2.707 76.956 1.008 2.476 8.704-12.549 8.552-32.56 10.141-12.403-.58-28.24.216-44.434.479-16.193.263-35.197-1.331-46.802-2.906z"
182 , fill: if theme.isLight then "#d8effd" else "url(#_Linear4)"
204 , fill: if theme.isLight then "#d8effd" else "url(#_Linear4)"
183− , className: classes.movingCloud2
205+ , css: classes.movingCloud2
206+ , className: "moving-cloud-2"
184 , transform: "translate(0 " <> show (scrolled * 20.0) <> ")"
207 , transform: "translate(0 " <> show (scrolled * 20.0) <> ")"
186 -- leftcloud
209 -- leftcloud
187− , SVG.path
210+ , E.element SVG.path'
188 { d: "M130.064 213.821c42.381 0 76.789.237 76.789 4.224 0 3.986-14.408 4.223-56.789 4.223-42.38 0-96.788.208-96.788-4.223s34.408-4.224 76.788-4.224z"
211 { d: "M130.064 213.821c42.381 0 76.789.237 76.789 4.224 0 3.986-14.408 4.223-56.789 4.223-42.38 0-96.788.208-96.788-4.223s34.408-4.224 76.788-4.224z"
189 , fill: if theme.isLight then "#d8effd" else "#a7847d"
212 , fill: if theme.isLight then "#d8effd" else "#a7847d"
190− , className: classes.movingCloud3
213+ , css: classes.movingCloud3
214+ , className: "moving-cloud-3"
191 , transform: "translate(0 " <> show (scrolled * 20.0) <> ")"
215 , transform: "translate(0 " <> show (scrolled * 20.0) <> ")"
193 , mountains theme.isLight scrolled
217 , mountains theme.isLight scrolled
@@ -195,7 +219,7 @@ mkLandingPageBackground = do
195 , buildings theme.isLight scrolled
219 , buildings theme.isLight scrolled
197 , SVG.path
221 , SVG.path
198− { fill: theme.backgroundColour # toHexString
222+ { fill: colour.background
199 , d: "M-3.028 431.298h826.844v20.006H-3.028z"
223 , d: "M-3.028 431.298h826.844v20.006H-3.028z"
201 -- laptop
225 -- laptop
@@ -208,16 +232,16 @@ mkLandingPageBackground = do
211− { cursor ∷ String
235+ { cursor ∷ E.Style
212− , keyword ∷ String
236+ , keyword ∷ E.Style
213− , laptopBackground ∷ String
237+ , laptopBackground ∷ E.Style
214− , laptopBody ∷ String
238+ , laptopBody ∷ E.Style
215− , screenText ∷ String
239+ , screenText ∷ E.Style
216− , typeName ∷ String
240+ , typeName ∷ E.Style
219 Number -> JSX
243 Number -> JSX
220−laptop classes scrolled =
244+laptop styles scrolled =
222 { children:
246 { children:
223 [ SVG.path
247 [ SVG.path
@@ -228,14 +252,16 @@ laptop classes scrolled =
228 { d: "M606.064 273.603c0-6.261-5.076-11.337-11.337-11.337H399.673c-6.261 0-11.337 5.076-11.337 11.337v151.521a5.001 5.001 0 005 5h207.728a5.004 5.004 0 003.536-1.464 5.004 5.004 0 001.464-3.536V273.603z"
252 { d: "M606.064 273.603c0-6.261-5.076-11.337-11.337-11.337H399.673c-6.261 0-11.337 5.076-11.337 11.337v151.521a5.001 5.001 0 005 5h207.728a5.004 5.004 0 003.536-1.464 5.004 5.004 0 001.464-3.536V273.603z"
229 , fill: "#657390"
253 , fill: "#657390"
231− , SVG.path
255+ , E.element SVG.path'
232 { d: "M599.193 275.905a5.528 5.528 0 00-5.526-5.526H400.604a5.528 5.528 0 00-5.526 5.526v141.039a5.528 5.528 0 005.526 5.526h193.063a5.528 5.528 0 005.526-5.526V275.905z"
256 { d: "M599.193 275.905a5.528 5.528 0 00-5.526-5.526H400.604a5.528 5.528 0 00-5.526 5.526v141.039a5.528 5.528 0 005.526 5.526h193.063a5.528 5.528 0 005.526-5.526V275.905z"
233 , fill: "#130c2b"
257 , fill: "#130c2b"
258+ , className: "laptop-background"
234− , className: classes.laptopBackground
259+ , css: styles.laptopBackground
236− , SVG.path
261+ , E.element SVG.path'
237 { d: "M655.04 427.228a.458.458 0 00-.457-.457H340.83v4.975a5 5 0 005 5h304.21a5 5 0 005-5v-4.518z"
262 { d: "M655.04 427.228a.458.458 0 00-.457-.457H340.83v4.975a5 5 0 005 5h304.21a5 5 0 005-5v-4.518z"
263+ , className: "laptop-body"
238− , className: classes.laptopBody
264+ , css: styles.laptopBody
240 , SVG.circle
266 , SVG.circle
241 { cx: "497.178"
267 { cx: "497.178"
@@ -256,12 +282,13 @@ laptop classes scrolled =
256 , fill: "#102708"
282 , fill: "#102708"
257 , fillOpacity: ".45"
283 , fillOpacity: ".45"
259− , SVG.text
285+ , E.element SVG.text'
260 { x: "407"
286 { x: "407"
261 , y: "290"
287 , y: "290"
262− , className: classes.screenText
288+ , css: styles.screenText
289+ , className: "screen-text"
263 , children:
290 , children:
264− textToTspans classes scrolled 407.0
291+ textToTspans styles scrolled 407.0
265 $ intercalate "\n"
292 $ intercalate "\n"
266 [ "hoistJoker "
293 [ "hoistJoker "
267 , "\t∷ ∀ f g a b"
294 , "\t∷ ∀ f g a b"
@@ -374,13 +401,13 @@ mountains isLight scrolled =
375textToTspans ∷
402textToTspans ∷
377− { cursor ∷ String
404+ { cursor ∷ E.Style
378− , keyword ∷ String
405+ , keyword ∷ E.Style
379− , typeName ∷ String
406+ , typeName ∷ E.Style
382 Number -> Number -> String -> Array JSX
409 Number -> Number -> String -> Array JSX
383−textToTspans classes scrolled x str = (foldl toTspan { distance: 0.0, acc: [] } lines).acc <> [ cursor ]
410+textToTspans styles scrolled x str = (foldl toTspan { distance: 0.0, acc: [] } lines).acc <> [ cursor ]
385 toTspan { distance, acc } line = case uncons (words line) of
412 toTspan { distance, acc } line = case uncons (words line) of
386 Nothing -> { distance: distance + 1.2, acc }
413 Nothing -> { distance: distance + 1.2, acc }
@@ -389,7 +416,6 @@ textToTspans classes scrolled x str = (foldl toTspan { distance: 0.0, acc: [] }
390 newElems ∷ Array JSX
417 newElems ∷ Array JSX
391 newElems = _.spans $ foldl mkNewElems { prefix: " ", spans: [] } tail
418 newElems = _.spans $ foldl mkNewElems { prefix: " ", spans: [] } tail
393 mkNewElems { prefix, spans } = case _ of
419 mkNewElems { prefix, spans } = case _ of
394 "" -> { prefix: prefix <> " ", spans }
420 "" -> { prefix: prefix <> " ", spans }
@@ -397,40 +423,40 @@ textToTspans classes scrolled x str = (foldl toTspan { distance: 0.0, acc: [] }
400− SVG.tspan
426+ E.element SVG.tspan'
401 { children: [ HTML.text $ prefix <> word ]
427 { children: [ HTML.text $ prefix <> word ]
402− , className: classNameForWord word
428+ , className: "word"
429+ , css: styleForWord word
407 SVG.tspan
433 SVG.tspan
408 { x: show x
434 { x: show x
409 , dy: show distance <> "em"
435 , dy: show distance <> "em"
410 , children: [ HTML.text head ]
436 , children: [ HTML.text head ]
413 pimped ∷ Array JSX
438 pimped ∷ Array JSX
414 pimped = first : newElems
439 pimped = first : newElems
415 { distance: 1.2, acc: acc <> pimped }
440 { distance: 1.2, acc: acc <> pimped }
416− classNameForWord = case _ of
441+
442+ styleForWord = case _ of
418− | elem keyword keywords -> classes.keyword
444+ | elem keyword keywords -> styles.keyword
420− | isTypeName typeName -> classes.typeName
446+ | isTypeName typeName -> styles.typeName
421− other -> ""
447+ other -> mempty
422 isTypeName s =
449 isTypeName s =
424 firstLetter = String.take 1 s
451 firstLetter = String.take 1 s
426 inRange c1 c2 = between (codePointFromChar c1) (codePointFromChar c2)
452 inRange c1 c2 = between (codePointFromChar c1) (codePointFromChar c2)
428 isLetter =
453 isLetter =
429 String.toCodePointArray
454 String.toCodePointArray
431 >>> maybe false (inRange 'a' 'z' || inRange 'A' 'Z')
456 >>> maybe false (inRange 'a' 'z' || inRange 'A' 'Z')
433 String.toUpper firstLetter == firstLetter && isLetter firstLetter
458 String.toUpper firstLetter == firstLetter && isLetter firstLetter
434 keywords =
460 keywords =
435 [ "module"
461 [ "module"
@@ -454,21 +480,28 @@ textToTspans classes scrolled x str = (foldl toTspan { distance: 0.0, acc: [] }
455 , "import"
481 , "import"
457 words line = split
484 words line = split
459 split = String.split (String.Pattern " ") line
486 split = String.split (String.Pattern " ") line
460 lines = String.split (String.Pattern "\n") scrolledString
488 lines = String.split (String.Pattern "\n") scrolledString
461 scrolledString = String.take charactersToTake str
490 scrolledString = String.take charactersToTake str
463 doneAfterXPercent = 0.5 -- [WARN] Don't set to 0
492 doneAfterXPercent = 0.5 -- [WARN] Don't set to 0
464 charactersToTake = round $ scrolled * (1.0 / doneAfterXPercent) * len
494 charactersToTake = round $ scrolled * (1.0 / doneAfterXPercent) * len
465 len = toNumber $ String.length str
496 len = toNumber $ String.length str
467− SVG.tspan
499+ E.element SVG.tspan'
468 { dx: "0"
500 { dx: "0"
469 , dy: "0"
501 , dy: "0"
470 , children: [ HTML.text "█" ]
502 , children: [ HTML.text "█" ]
503+ , css: styles.cursor
471− , className: classes.cursor
504+ , className: "landing-page-cursor"
472 , id: "landing-page-cursor"
505 , id: "landing-page-cursor"
@@ -894,43 +927,38 @@ darkDefs =
895infixr 8 zip as <%>
928infixr 8 zip as <%>
897−stars ∷ ∀ css. String -> { twinklingStar1 ∷ String, twinklingStar2 ∷ String, twinklingStar3 ∷ String | css } -> JSX
930+stars ∷ ∀ css. E.Style -> { twinklingStar1 ∷ E.Style, twinklingStar2 ∷ E.Style, twinklingStar3 ∷ E.Style | css } -> JSX
898−stars className classes =
931+stars starStyle allStyles =
902 xs = randomRs 0.0 800.0 n $ mkSeed 84
934 xs = randomRs 0.0 800.0 n $ mkSeed 84
904 ys = randomRs (-20.0) 200.0 n $ mkSeed 4398
935 ys = randomRs (-20.0) 200.0 n $ mkSeed 4398
906 radiuses = randomRs 0.1 1.3 n (mkSeed 15)
936 radiuses = randomRs 0.1 1.3 n (mkSeed 15)
908 opacities = randomRs 0.5 0.9 n (mkSeed 92)
937 opacities = randomRs 0.5 0.9 n (mkSeed 92)
911 randomRs 1 50 n (mkSeed 3)
939 randomRs 1 50 n (mkSeed 3)
912 <#> case _ of
940 <#> case _ of
913− 1 -> classes.twinklingStar1
941+ 1 -> allStyles.twinklingStar1
914− 2 -> classes.twinklingStar2
942+ 2 -> allStyles.twinklingStar2
915− 3 -> classes.twinklingStar2
943+ 3 -> allStyles.twinklingStar2
916− _ -> ""
944+ _ -> mempty
918− zipped = xs <%> ys <%> radiuses <%> classNames <%> opacities
945+ zipped = xs <%> ys <%> radiuses <%> styles <%> opacities
920 children = do
946 children = do
921 cx /\ cy /\ r /\ className' /\ opacity <- zipped
947 cx /\ cy /\ r /\ className' /\ opacity <- zipped
923− $ SVG.circle
949+ $ E.element SVG.circle'
924 { cx: show cx
950 { cx: show cx
925 , cy: show cy
951 , cy: show cy
926 , r: show r
952 , r: show r
927 , fill: "#eeefff"
953 , fill: "#eeefff"
928− , className: className'
954+ , css: className'
955+ , className: "starry" -- [TODO]
929 , opacity: show (opacity - cy / 200.0)
956 , opacity: show (opacity - cy / 200.0)
932− SVG.g
959+ E.element SVG.g'
933 { fillOpacity: ".67"
960 { fillOpacity: ".67"
934 , children
961 , children
935− , className
963+ , className: "star-g"