git.iko.soy/typeable/elm-ui
on master help sign in
365 lines 11 kB history raw
1module Main exposing (main)
3{-| Line Height as its specified through CSS doesn't make a whole lot of sense typographically.
5We also run into issues with sizing a font. The font size generally refers to the full type size (from the top of ascendors to the bottom of descenders)
7However, sometimes we might want to size things from the top of the Capital to the baseline.
9Or from the top of the x-height to the baseline.
11The main place this shows up is for dropped capitals, and for text on buttons.
13-}
15import Browser
16import Element exposing (..)
17import Element.Background as Background
18import Element.Border as Border
19import Element.Font as Font
20import Element.Input as Input
21import Element.Lazy
22import Html.Attributes
25type alias FontAdjustment =
26 { lineHeight : Float
27 , capital : Line
28 , lowercase : Line
29 , baseline : Line
30 , descender : Line
31 }
34type alias Line =
35 Float
38type Msg
39 = UpdateAdjustment FontAdjustment
42edges =
43 { top = 0
44 , right = 0
45 , bottom = 0
46 , left = 0
47 }
50default =
51 { capital = 1.15
52 , lowercase = 0.96
53 , baseline = 0.465
54 , descender = 0.245
55 , lineHeight = 1.5
56 }
59init =
60 { adjustment =
61 default
62 , converted =
63 convertAdjustment default
64 }
67update msg model =
68 case msg of
69 UpdateAdjustment adj ->
70 { model
71 | adjustment = adj
72 , converted = convertAdjustment adj
73 }
76main =
77 Browser.sandbox
78 { init = init
79 , update = update
80 , view = view
81 }
84view model =
85 Element.layout
86 [ Background.color (rgba 1 1 1 1)
87 , Font.color (rgba 0 0 0 1)
88 , Font.family
89 [ -- Font.external
90 -- { url = "https://fonts.googleapis.com/css?family=EB+Garamond"
91 -- , name = "EB Garamond"
92 -- }
93 Font.external
94 { url = "https://fonts.googleapis.com/css?family=Catamaran"
95 , name = "Catamaran"
96 }
97 , Font.sansSerif
98 ]
99 ]
100 <|
101 column [ width fill, height fill, spacing 128 ]
102 [ adjustor 120 model.adjustment
103 , adjusted 120 model.converted
104 ]
107style name val =
108 htmlAttribute (Html.Attributes.style name val)
111fontSize pixels lineHeight up =
112 [ Font.size pixels
114 -- , htmlAttribute (Html.Attributes.style "line-height" lineHeight)
115 -- , Background.color (rgb 0 0.8 0.9)
116 -- , onLeft
117 -- (el
118 -- [ Background.color (rgb 0 0 0)
119 -- , width (px 20)
120 -- , height (px pixels)
121 -- , moveUp up
122 -- ]
123 -- none
124 -- )
125 ]
128charcoal =
129 rgb 0.7 0.7 0.7
132adjustor size adjustment =
133 let
134 labels =
135 [ viewAdjustment "Type Height" adjustment.capital size 180 adjustment.lineHeight (\capital -> { adjustment | capital = capital })
136 , viewAdjustment "Lowercase Height" adjustment.lowercase size 60 adjustment.lineHeight (\lowercase -> { adjustment | lowercase = lowercase })
137 , viewAdjustment "Baseline" adjustment.baseline size 120 adjustment.lineHeight (\baseline -> { adjustment | baseline = baseline })
138 , viewAdjustment "Descender" adjustment.descender size 0 adjustment.lineHeight (\descender -> { adjustment | descender = descender })
139 ]
140 in
141 el
142 ([ centerX
143 , centerY
144 , Background.color (rgb 0 0.8 0.9)
145 , style "line-height" (String.fromFloat adjustment.lineHeight)
146 , onRight
147 (el
148 [ centerY
149 , width (px 40)
151 -- , height (px (round (toFloat size * (1 / 1.5))))
152 , height (px size)
153 , Background.color (rgb 0.9 0.8 0)
154 ]
155 none
156 )
157 , Font.size size
158 ]
159 ++ labels
160 )
161 (text "Typography")
164adjusted size adjustment =
165 column
166 [ spacing 48
167 , centerX
168 , centerY
169 ]
170 [ row
171 [ spacing 32
172 , Font.size 120
173 , above (text "hi")
174 ]
175 [ el
176 [ Background.color (rgb 0 0.8 0.9)
177 , style "line-height" "normal"
178 , above (el [ Font.size 12 ] (text "line-height: normal"))
179 ]
180 (text "Typography")
181 , el
182 [ Background.color (rgb 0 0.8 0.9)
183 , style "line-height" "1"
184 , above (el [ Font.size 12 ] (text "line-height: 1"))
185 ]
186 (text "Typography")
187 ]
188 , row
189 [ spacing 32
190 , Font.size 120
191 ]
192 [ corrected adjustment.full "corrected"
193 , corrected adjustment.capital "corrected capital"
194 ]
195 , paragraph [ Font.size 25, spacing 5, width (px 200) ]
196 [ el [ Font.size 55, alignLeft ] (text "L")
197 , text "orem Ipsum is simply dummy text of the printing and typesetting industry."
198 ]
199 ]
202corrected converted label =
203 el
204 [ Background.color (rgb 0 0.8 0.9)
205 , style "display" "block"
206 , above (el [ Font.size 12, moveUp 6 ] (text label))
207 , style "line-height" (String.fromFloat converted.height)
208 , below
209 (column [ Font.size 12, spacing 5, moveDown 10 ]
210 [ text ("height: " ++ String.left 5 (String.fromFloat converted.height))
211 , text ("vertical: " ++ String.left 5 (String.fromFloat converted.vertical))
212 ]
213 )
214 ]
215 (el
216 [ style "display" "inline-block"
217 , style "line-height" (String.fromFloat converted.height)
218 , style "vertical-align" (String.fromFloat converted.vertical ++ "em")
219 ]
220 (text "Typography")
221 )
224convertAdjustment adjustment =
225 let
226 base =
227 adjustment.lineHeight
229 normalDescender =
230 (adjustment.lineHeight - 1)
231 / 2
233 oldMiddle =
234 adjustment.lineHeight / 2
236 newCapitalMiddle =
237 ((ascender - newBaseline) / 2) + newBaseline
239 newFullMiddle =
240 ((ascender - descender) / 2) + descender
242 lines =
243 [ adjustment.capital
244 , adjustment.baseline
245 , adjustment.descender
246 , adjustment.lowercase
247 ]
249 ascender =
250 Maybe.withDefault adjustment.capital (List.maximum lines)
252 descender =
253 Maybe.withDefault adjustment.descender (List.minimum lines)
255 newBaseline =
256 lines
257 |> List.filter (\x -> x /= descender)
258 |> List.minimum
259 |> Maybe.withDefault adjustment.baseline
261 capitalVertical =
262 (oldMiddle - newCapitalMiddle) * 2
264 fullVertical =
265 (oldMiddle - newFullMiddle) * 2
266 in
267 { full =
268 { vertical = fullVertical
269 , height =
270 (ascender - descender)
271 - abs fullVertical
272 }
273 , capital =
274 { vertical = capitalVertical
275 , height = (ascender - newBaseline) - abs capitalVertical
276 }
277 }
280viewAdjustment label adjustment size left lineHeight updateWith =
281 let
282 fullHeight =
283 toFloat size * 1.5
284 in
285 onLeft
286 (el
287 [ moveLeft left
289 -- , moveUp (0.125 * toFloat size)
290 , height (px (round (toFloat size * lineHeight)))
291 ]
292 <|
293 Input.slider
294 [ Font.size 24
295 , Element.behindContent
296 (Element.el
297 [ Element.width (Element.px 1)
298 , Element.height Element.fill
299 , Element.centerY
300 , Background.color charcoal
301 , Border.rounded 2
302 ]
303 Element.none
304 )
305 , height (px (round fullHeight))
306 , width (px 1)
307 , spacing 0
308 , Background.color charcoal
309 , below (el [ centerX ] (text (String.fromFloat adjustment)))
310 , onRight
311 (el
312 [ height (px 0)
313 , width (px 800)
314 , moveRight 10
315 , alignBottom
316 , moveUp (fullHeight * (adjustment / lineHeight))
317 , Border.color (rgb 0 0 0)
318 , Border.dashed
319 , Border.widthEach
320 { top = 1
321 , right = 0
322 , bottom = 0
323 , left = 0
324 }
325 ]
326 none
327 )
328 ]
329 { label = Input.labelAbove [ Font.size 18 ] (text "")
330 , max = lineHeight
331 , min = 0
332 , onChange =
333 \x ->
334 UpdateAdjustment
335 (updateWith x)
336 , step = Just 0.005
337 , thumb =
338 Input.thumb
339 [ Element.width (Element.px 16)
340 , Element.height (Element.px 16)
341 , Border.rounded 8
342 , Border.width 1
343 , Border.color (Element.rgb 0.5 0.5 0.5)
344 , Background.color (Element.rgb 1 1 1)
346 -- , onRight
347 -- (el
348 -- [ height (px 0)
349 -- , width (px 1200)
350 -- , moveDown 8
351 -- , Border.color (rgb 0 0 0)
352 -- , Border.dashed
353 -- , Border.widthEach
354 -- { top = 1
355 -- , right = 0
356 -- , bottom = 0
357 -- , left = 0
358 -- }
359 -- ]
360 -- none
361 -- )
362 ]
363 , value = adjustment
364 }
365 )