diff options
author | Akshay <[email protected]> | 2020-11-23 14:01:15 +0000 |
---|---|---|
committer | Akshay <[email protected]> | 2020-11-23 14:01:15 +0000 |
commit | 615f4398f2b118a0142d752433d7eb1fc77f2301 (patch) | |
tree | 8b63898317c63d854cfdd22404b69375f417f0a5 | |
parent | 86bd94ec91e88f3a50a02daf051fcca316db09a5 (diff) |
fix layouting, finish styling
-rw-r--r-- | src/Base.elm | 1 | ||||
-rw-r--r-- | src/Main.elm | 59 | ||||
-rw-r--r-- | src/Styles.elm | 87 | ||||
-rw-r--r-- | src/Views.elm | 83 |
4 files changed, 149 insertions, 81 deletions
diff --git a/src/Base.elm b/src/Base.elm index 480147a..1d19723 100644 --- a/src/Base.elm +++ b/src/Base.elm | |||
@@ -25,6 +25,7 @@ type alias Model = | |||
25 | , config : Config | 25 | , config : Config |
26 | , currentWord : Int | 26 | , currentWord : Int |
27 | , inputBox : String | 27 | , inputBox : String |
28 | , inputCorrect : Bool | ||
28 | } | 29 | } |
29 | 30 | ||
30 | 31 | ||
diff --git a/src/Main.elm b/src/Main.elm index 4ca4934..2b1cc67 100644 --- a/src/Main.elm +++ b/src/Main.elm | |||
@@ -4,14 +4,14 @@ import Array exposing (..) | |||
4 | import Base exposing (..) | 4 | import Base exposing (..) |
5 | import Browser | 5 | import Browser |
6 | import Css | 6 | import Css |
7 | import Css.Global exposing (everything, global, selector) | 7 | import Css.Global exposing (body, everything, global, selector) |
8 | import Data exposing (..) | 8 | import Data exposing (..) |
9 | import Html | 9 | import Html |
10 | import Html.Styled exposing (..) | 10 | import Html.Styled exposing (..) |
11 | import Html.Styled.Attributes exposing (..) | 11 | import Html.Styled.Attributes exposing (..) |
12 | import Html.Styled.Events exposing (onClick, onInput) | 12 | import Html.Styled.Events exposing (onClick, onInput) |
13 | import Random | 13 | import Random |
14 | import Styles exposing (styledButton, styledInput, styledTextBox) | 14 | import Styles exposing (styledButton, styledInput, styledTextBox, wordStyle) |
15 | import Task | 15 | import Task |
16 | import Time | 16 | import Time |
17 | import Utils exposing (isJust, isNothing) | 17 | import Utils exposing (isJust, isNothing) |
@@ -44,7 +44,7 @@ generateWords config = | |||
44 | 44 | ||
45 | defaultModel : Model | 45 | defaultModel : Model |
46 | defaultModel = | 46 | defaultModel = |
47 | Model Nothing Nothing Array.empty Nothing defaultConfig 0 "" | 47 | Model Nothing Nothing Array.empty Nothing defaultConfig 0 "" False |
48 | 48 | ||
49 | 49 | ||
50 | init : () -> ( Model, Cmd Msg ) | 50 | init : () -> ( Model, Cmd Msg ) |
@@ -143,8 +143,11 @@ update msg model = | |||
143 | 143 | ||
144 | else | 144 | else |
145 | Cmd.none | 145 | Cmd.none |
146 | |||
147 | inpStat = | ||
148 | String.startsWith s (currentContents model) | ||
146 | in | 149 | in |
147 | ( { model | inputBox = s } | 150 | ( { model | inputBox = s, inputCorrect = inpStat } |
148 | , cmd | 151 | , cmd |
149 | ) | 152 | ) |
150 | 153 | ||
@@ -183,28 +186,13 @@ update msg model = | |||
183 | ) | 186 | ) |
184 | 187 | ||
185 | 188 | ||
186 | wordStyle : WordStatus -> Attribute msg | ||
187 | wordStyle w = | ||
188 | case w of | ||
189 | Correct -> | ||
190 | style "color" "green" | ||
191 | |||
192 | Wrong -> | ||
193 | style "color" "red" | ||
194 | |||
195 | Todo -> | ||
196 | style "color" "black" | ||
197 | |||
198 | CurrentWord -> | ||
199 | style "color" "magenta" | ||
200 | |||
201 | |||
202 | toPara : Array Word -> Int -> String -> Html Msg | 189 | toPara : Array Word -> Int -> String -> Html Msg |
203 | toPara words current content = | 190 | toPara words current content = |
204 | words | 191 | words |
205 | |> Array.map (\w -> span [ wordStyle w.status ] [ text (w.content ++ " ") ]) | 192 | |> Array.map (\w -> span [ css [ wordStyle w.status ] ] [ text w.content ]) |
206 | |> Array.set current (span [ wordStyle CurrentWord ] [ text (content ++ " ") ]) | 193 | |> Array.set current (span [ css [ wordStyle CurrentWord ] ] [ text content ]) |
207 | |> Array.toList | 194 | |> Array.toList |
195 | |> List.intersperse (span [] [ text " " ]) | ||
208 | |> styledTextBox [] | 196 | |> styledTextBox [] |
209 | 197 | ||
210 | 198 | ||
@@ -217,20 +205,33 @@ currentContents model = | |||
217 | 205 | ||
218 | view : Model -> Html Msg | 206 | view : Model -> Html Msg |
219 | view model = | 207 | view model = |
220 | div [] | 208 | div |
221 | [ div [] | 209 | [ style "width" "95%" |
210 | , style "max-width" "650px" | ||
211 | , style "margin" "auto" | ||
212 | , style "padding-top" "15%" | ||
213 | ] | ||
214 | [ div | ||
215 | [ style "width" "100%" | ||
216 | ] | ||
222 | [ viewWordLengthOptions | 217 | [ viewWordLengthOptions |
223 | , viewStats model | 218 | , div |
219 | [ style "float" "right" ] | ||
220 | [ styledButton [ onClick Redo ] [ text "redo" ] ] | ||
224 | ] | 221 | ] |
225 | , div [] | 222 | , div [] |
226 | [ toPara model.words model.currentWord (currentContents model) | 223 | [ toPara model.words model.currentWord (currentContents model) |
227 | , div [] | 224 | , div [] |
228 | [ styledInput [ onInput handleInputChanged, value model.inputBox ] [] | 225 | [ text "> " |
229 | , styledButton [ onClick Redo ] [ text "redo" ] | 226 | , styledInput model.inputCorrect [ onInput handleInputChanged, value model.inputBox ] [] |
230 | ] | 227 | ] |
231 | ] | 228 | ] |
232 | , global [ selector "li:not(:last-child)::after" [ Css.property "content" "' / '" ] ] | 229 | , div [] [ viewStats model ] |
233 | , global [ everything [ Css.fontFamily Css.monospace ] ] | 230 | |
231 | -- , global [ selector "li:not(:last-child)::after" [ Css.property "content" "' · '" ] ] | ||
232 | , global [ everything [ Css.fontFamily Css.monospace, Css.fontSize (Css.px 18) ] ] | ||
233 | |||
234 | -- , global [ body [ Css.backgroundColor (Css.hex "#000"), Css.color (Css.hex "#fff") ] ] | ||
234 | ] | 235 | ] |
235 | 236 | ||
236 | 237 | ||
diff --git a/src/Styles.elm b/src/Styles.elm index 36bd1a3..db5b0ce 100644 --- a/src/Styles.elm +++ b/src/Styles.elm | |||
@@ -1,5 +1,6 @@ | |||
1 | module Styles exposing (..) | 1 | module Styles exposing (..) |
2 | 2 | ||
3 | import Base exposing (WordStatus(..)) | ||
3 | import Css exposing (..) | 4 | import Css exposing (..) |
4 | import Css.Global exposing (global, selector) | 5 | import Css.Global exposing (global, selector) |
5 | import Html | 6 | import Html |
@@ -10,27 +11,43 @@ styledButton : List (Attribute msg) -> List (Html msg) -> Html msg | |||
10 | styledButton = | 11 | styledButton = |
11 | styled | 12 | styled |
12 | button | 13 | button |
13 | [ margin (px 12) | 14 | [ marginTop (px 12) |
14 | , color (hex "#000") | 15 | , marginBottom (px 12) |
16 | , paddingTop (px 12) | ||
17 | , paddingBottom (px 12) | ||
18 | , paddingLeft (px 0) | ||
19 | , paddingRight (px 12) | ||
15 | , fontFamily monospace | 20 | , fontFamily monospace |
16 | , backgroundColor (hex "#ddd") | ||
17 | , border (px 0) | 21 | , border (px 0) |
22 | , backgroundColor (hex "#fff") | ||
18 | , borderRadius (px 4) | 23 | , borderRadius (px 4) |
19 | , padding (px 12) | ||
20 | ] | 24 | ] |
21 | 25 | ||
22 | 26 | ||
23 | styledInput : List (Attribute msg) -> List (Html msg) -> Html msg | 27 | correctInputStyle : Style |
24 | styledInput = | 28 | correctInputStyle = |
29 | color (hex "#000") | ||
30 | |||
31 | |||
32 | wrongInputStyle : Style | ||
33 | wrongInputStyle = | ||
34 | wrongWordStyle | ||
35 | |||
36 | |||
37 | styledInput : Bool -> List (Attribute msg) -> List (Html msg) -> Html msg | ||
38 | styledInput inputStatus = | ||
25 | styled | 39 | styled |
26 | input | 40 | input |
27 | [ margin (px 12) | 41 | [ fontFamily monospace |
28 | , color (hex "#000") | 42 | , if inputStatus then |
29 | , fontFamily monospace | 43 | correctInputStyle |
30 | , backgroundColor (hex "#eee") | 44 | |
31 | , border (px 0) | 45 | else |
32 | , borderRadius (px 4) | 46 | wrongInputStyle |
33 | , padding (px 12) | 47 | , border zero |
48 | , paddingTop (px 12) | ||
49 | , paddingBottom (px 12) | ||
50 | , width (pct 95) | ||
34 | ] | 51 | ] |
35 | 52 | ||
36 | 53 | ||
@@ -55,14 +72,12 @@ styledTextBox : List (Attribute msg) -> List (Html msg) -> Html msg | |||
55 | styledTextBox = | 72 | styledTextBox = |
56 | styled | 73 | styled |
57 | div | 74 | div |
58 | [ margin (px 12) | 75 | [ color (hex "#000") |
59 | , color (hex "#000") | ||
60 | , fontFamily monospace | 76 | , fontFamily monospace |
61 | , backgroundColor (hex "#eee") | ||
62 | , border (px 0) | 77 | , border (px 0) |
63 | , borderRadius (px 4) | 78 | , borderRadius (px 4) |
64 | , padding (px 12) | 79 | , paddingTop (px 12) |
65 | , width (px 500) | 80 | , paddingBottom (px 12) |
66 | , display inlineBlock | 81 | , display inlineBlock |
67 | ] | 82 | ] |
68 | 83 | ||
@@ -74,3 +89,39 @@ actionContainer = | |||
74 | [ padding (px 12) | 89 | [ padding (px 12) |
75 | , width (pct 100) | 90 | , width (pct 100) |
76 | ] | 91 | ] |
92 | |||
93 | |||
94 | wrongWordStyle : Style | ||
95 | wrongWordStyle = | ||
96 | color (hex "#f07178") | ||
97 | |||
98 | |||
99 | correctWordStyle : Style | ||
100 | correctWordStyle = | ||
101 | color (hex "#13CA91") | ||
102 | |||
103 | |||
104 | todoWordStyle : Style | ||
105 | todoWordStyle = | ||
106 | color (hex "#787878") | ||
107 | |||
108 | |||
109 | currentWordStyle : Style | ||
110 | currentWordStyle = | ||
111 | textDecoration underline | ||
112 | |||
113 | |||
114 | wordStyle : WordStatus -> Style | ||
115 | wordStyle w = | ||
116 | case w of | ||
117 | Correct -> | ||
118 | correctWordStyle | ||
119 | |||
120 | Wrong -> | ||
121 | wrongWordStyle | ||
122 | |||
123 | Todo -> | ||
124 | todoWordStyle | ||
125 | |||
126 | CurrentWord -> | ||
127 | currentWordStyle | ||
diff --git a/src/Views.elm b/src/Views.elm index b56a945..b54fc93 100644 --- a/src/Views.elm +++ b/src/Views.elm | |||
@@ -5,10 +5,11 @@ import Base exposing (..) | |||
5 | import Css exposing (..) | 5 | import Css exposing (..) |
6 | import Html | 6 | import Html |
7 | import Html.Styled exposing (..) | 7 | import Html.Styled exposing (..) |
8 | import Html.Styled.Attributes exposing (css) | ||
8 | import Html.Styled.Events exposing (onClick) | 9 | import Html.Styled.Events exposing (onClick) |
9 | import Styles exposing (styledListItem, styledUnorderedList) | 10 | import Styles exposing (styledButton, styledListItem, styledUnorderedList) |
10 | import Time exposing (Posix, toHour, toMinute, toSecond, utc) | 11 | import Time exposing (Posix, toHour, toMinute, toSecond, utc) |
11 | import Utils exposing (diffDuration, wordCountWith) | 12 | import Utils exposing (diffDuration, isNothing, wordCountWith) |
12 | 13 | ||
13 | 14 | ||
14 | viewTime : Posix -> String | 15 | viewTime : Posix -> String |
@@ -26,7 +27,7 @@ viewTime t = | |||
26 | String.join ":" (List.map String.fromInt [ hh, mm, ss ]) | 27 | String.join ":" (List.map String.fromInt [ hh, mm, ss ]) |
27 | 28 | ||
28 | 29 | ||
29 | viewWpm : Model -> String | 30 | viewWpm : Model -> Maybe String |
30 | viewWpm model = | 31 | viewWpm model = |
31 | let | 32 | let |
32 | t1 = | 33 | t1 = |
@@ -40,11 +41,8 @@ viewWpm model = | |||
40 | 41 | ||
41 | correctWords = | 42 | correctWords = |
42 | wordCountWith model.words ((==) Correct) | 43 | wordCountWith model.words ((==) Correct) |
43 | |||
44 | wpm = | ||
45 | Maybe.map (String.fromInt << truncate << (*) 60 << (/) (toFloat correctWords)) duration | ||
46 | in | 44 | in |
47 | Maybe.withDefault "XX" wpm | 45 | Maybe.map (String.fromInt << truncate << (*) 60 << (/) (toFloat correctWords)) duration |
48 | 46 | ||
49 | 47 | ||
50 | viewProgress : Model -> String | 48 | viewProgress : Model -> String |
@@ -59,28 +57,30 @@ viewProgress model = | |||
59 | String.fromInt soFar ++ ":" ++ String.fromInt total | 57 | String.fromInt soFar ++ ":" ++ String.fromInt total |
60 | 58 | ||
61 | 59 | ||
62 | viewAccuracy : Array Word -> String | 60 | viewAccuracy : Model -> Maybe String |
63 | viewAccuracy words = | 61 | viewAccuracy model = |
64 | let | 62 | if isNothing model.end then |
65 | wordsAttempted = | 63 | Nothing |
66 | toFloat <| wordCountWith words ((/=) Todo) | ||
67 | 64 | ||
68 | correctCount = | 65 | else |
69 | toFloat <| wordCountWith words ((==) Correct) | 66 | let |
67 | words = | ||
68 | model.words | ||
70 | 69 | ||
71 | accuracy = | 70 | wordsAttempted = |
72 | if wordsAttempted == 0.0 then | 71 | toFloat <| wordCountWith words ((/=) Todo) |
73 | Nothing | ||
74 | 72 | ||
75 | else | 73 | correctCount = |
76 | Just <| correctCount / wordsAttempted * 100 | 74 | toFloat <| wordCountWith words ((==) Correct) |
77 | in | 75 | |
78 | case accuracy of | 76 | accuracy = |
79 | Nothing -> | 77 | if wordsAttempted == 0.0 then |
80 | "XX" | 78 | Nothing |
81 | 79 | ||
82 | Just a -> | 80 | else |
83 | String.fromInt <| truncate a | 81 | Just <| String.fromInt <| truncate <| correctCount / wordsAttempted * 100 |
82 | in | ||
83 | accuracy | ||
84 | 84 | ||
85 | 85 | ||
86 | viewWordLengthOptions : Html Msg | 86 | viewWordLengthOptions : Html Msg |
@@ -89,12 +89,20 @@ viewWordLengthOptions = | |||
89 | wl = | 89 | wl = |
90 | [ 10, 25, 50, 100 ] | 90 | [ 10, 25, 50, 100 ] |
91 | in | 91 | in |
92 | styledUnorderedList [] | 92 | ul |
93 | [ css | ||
94 | [ margin zero | ||
95 | , listStyle Css.none | ||
96 | , display inlineBlock | ||
97 | , paddingLeft (px 0) | ||
98 | ] | ||
99 | ] | ||
93 | (List.map | 100 | (List.map |
94 | (\len -> | 101 | (\len -> |
95 | styledListItem | 102 | li [ css [ display inline ] ] |
96 | [ onClick (Base.WordLengthChanged len) ] | 103 | [ styledButton [ onClick (Base.WordLengthChanged len) ] |
97 | [ text <| String.fromInt len ] | 104 | [ text <| String.fromInt len ] |
105 | ] | ||
98 | ) | 106 | ) |
99 | wl | 107 | wl |
100 | ) | 108 | ) |
@@ -102,8 +110,15 @@ viewWordLengthOptions = | |||
102 | 110 | ||
103 | viewStats : Model -> Html Msg | 111 | viewStats : Model -> Html Msg |
104 | viewStats model = | 112 | viewStats model = |
105 | styledUnorderedList [] | 113 | let |
106 | [ styledListItem [] [ text ("WPM " ++ viewWpm model) ] | 114 | wpm = |
107 | , styledListItem [] [ text ("ACC " ++ viewAccuracy model.words) ] | 115 | viewWpm model |
108 | , styledListItem [] [ text ("POS " ++ viewProgress model) ] | 116 | |
109 | ] | 117 | acc = |
118 | viewAccuracy model | ||
119 | |||
120 | stats = | ||
121 | Maybe.map2 (\w a -> w ++ " words per minute · " ++ a ++ "% accuracy") wpm acc | ||
122 | in | ||
123 | p [] | ||
124 | [ text (Maybe.withDefault "" stats) ] | ||