about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--website/sandbox/chord-drill-sergeant/.gitignore4
-rw-r--r--website/sandbox/chord-drill-sergeant/README.md2
-rw-r--r--website/sandbox/chord-drill-sergeant/index.css3
-rw-r--r--website/sandbox/chord-drill-sergeant/index.html15
-rw-r--r--website/sandbox/chord-drill-sergeant/shell.nix1
-rw-r--r--website/sandbox/chord-drill-sergeant/src/Main.elm228
-rw-r--r--website/sandbox/chord-drill-sergeant/src/Tempo.elm21
-rw-r--r--website/sandbox/chord-drill-sergeant/src/UI.elm116
8 files changed, 264 insertions, 126 deletions
diff --git a/website/sandbox/chord-drill-sergeant/.gitignore b/website/sandbox/chord-drill-sergeant/.gitignore
index 8b0d053e4e35..aa247dd183c9 100644
--- a/website/sandbox/chord-drill-sergeant/.gitignore
+++ b/website/sandbox/chord-drill-sergeant/.gitignore
@@ -1 +1,3 @@
-/elm-stuff
\ No newline at end of file
+/elm-stuff
+/elm.js
+/output.css
\ No newline at end of file
diff --git a/website/sandbox/chord-drill-sergeant/README.md b/website/sandbox/chord-drill-sergeant/README.md
index 0f9dd4d6bc6e..9ed3dae91a68 100644
--- a/website/sandbox/chord-drill-sergeant/README.md
+++ b/website/sandbox/chord-drill-sergeant/README.md
@@ -53,5 +53,5 @@ in which you can develop:
 
 ```shell
 $ nix-shell
-$ elm reactor
+$ elm-live -- src/Main.elm --output=elm.js
 ```
diff --git a/website/sandbox/chord-drill-sergeant/index.css b/website/sandbox/chord-drill-sergeant/index.css
new file mode 100644
index 000000000000..b5c61c956711
--- /dev/null
+++ b/website/sandbox/chord-drill-sergeant/index.css
@@ -0,0 +1,3 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
diff --git a/website/sandbox/chord-drill-sergeant/index.html b/website/sandbox/chord-drill-sergeant/index.html
new file mode 100644
index 000000000000..d2218ea1905a
--- /dev/null
+++ b/website/sandbox/chord-drill-sergeant/index.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8" />
+    <title>Chord Drill Sergeant</title>
+    <link rel="stylesheet" href="./output.css" />
+    <script src="./elm.js"></script>
+  </head>
+  <body class="font-serif">
+    <div id="mount"></div>
+    <script>
+     Elm.Main.init({node: document.getElementById("mount")});
+    </script>
+  </body>
+</html>
diff --git a/website/sandbox/chord-drill-sergeant/shell.nix b/website/sandbox/chord-drill-sergeant/shell.nix
index 584b6c4a9e84..6f1c8ee23b30 100644
--- a/website/sandbox/chord-drill-sergeant/shell.nix
+++ b/website/sandbox/chord-drill-sergeant/shell.nix
@@ -4,5 +4,6 @@ in pkgs.mkShell {
   buildInputs = with pkgs; [
     elmPackages.elm
     elmPackages.elm-format
+    elmPackages.elm-live
   ];
 }
diff --git a/website/sandbox/chord-drill-sergeant/src/Main.elm b/website/sandbox/chord-drill-sergeant/src/Main.elm
index ebbc523333af..f13412a0a9f4 100644
--- a/website/sandbox/chord-drill-sergeant/src/Main.elm
+++ b/website/sandbox/chord-drill-sergeant/src/Main.elm
@@ -1,17 +1,16 @@
 module Main exposing (main)
 
 import Browser
-import ChordInspector
 import Html exposing (..)
 import Html.Attributes exposing (..)
 import Html.Events exposing (..)
-import NoteInspector
 import Piano
 import Random
 import Random.List
 import Tempo
 import Theory
 import Time exposing (..)
+import UI
 
 
 type alias Model =
@@ -26,13 +25,15 @@ type alias Model =
     , firstNote : Theory.Note
     , lastNote : Theory.Note
     , practiceMode : PracticeMode
-    , debug :
-        { enable : Bool
-        , inspectChord : Bool
-        }
+    , view : View
     }
 
 
+type View
+    = Preferences
+    | Practice
+
+
 {-| Control the type of practice you'd like.
 -}
 type PracticeMode
@@ -48,7 +49,6 @@ type Msg
     | IncreaseTempo
     | DecreaseTempo
     | SetTempo String
-    | ToggleInspectChord
     | ToggleInversion Theory.ChordInversion
     | ToggleChordType Theory.ChordType
     | TogglePitchClass Theory.PitchClass
@@ -84,7 +84,7 @@ init : Model
 init =
     let
         ( firstNote, lastNote ) =
-            ( Theory.C3, Theory.C5 )
+            ( Theory.A1, Theory.C8 )
 
         inversions =
             Theory.allInversions
@@ -96,7 +96,7 @@ init =
             Theory.allPitchClasses
 
         keys =
-            Theory.allKeys
+            []
 
         practiceMode =
             KeyMode
@@ -121,13 +121,10 @@ init =
     , whitelistedKeys = keys
     , selectedChord = Nothing
     , isPaused = True
-    , tempo = 60
+    , tempo = 30
     , firstNote = firstNote
     , lastNote = lastNote
-    , debug =
-        { enable = False
-        , inspectChord = True
-        }
+    , view = Preferences
     }
 
 
@@ -212,16 +209,6 @@ update msg model =
             , Cmd.none
             )
 
-        ToggleInspectChord ->
-            ( { model
-                | debug =
-                    { inspectChord = not model.debug.inspectChord
-                    , enable = model.debug.enable
-                    }
-              }
-            , Cmd.none
-            )
-
         ToggleChordType chordType ->
             let
                 chordTypes =
@@ -331,33 +318,6 @@ playPause { isPaused } =
         button [ onClick Pause ] [ text "Pause" ]
 
 
-debugger : Html Msg
-debugger =
-    fieldset []
-        [ label [] [ text "Inspect Chord" ]
-        , input [ type_ "checkbox", onClick ToggleInspectChord, checked init.debug.inspectChord ] []
-        ]
-
-
-pitchClassCheckboxes : List Theory.PitchClass -> Html Msg
-pitchClassCheckboxes pitchClasses =
-    ul []
-        (Theory.allPitchClasses
-            |> List.map
-                (\pitchClass ->
-                    li []
-                        [ label [] [ text (Theory.viewPitchClass pitchClass) ]
-                        , input
-                            [ type_ "checkbox"
-                            , onClick (TogglePitchClass pitchClass)
-                            , checked (List.member pitchClass pitchClasses)
-                            ]
-                            []
-                        ]
-                )
-        )
-
-
 chordTypeCheckboxes : List Theory.ChordType -> Html Msg
 chordTypeCheckboxes chordTypes =
     ul []
@@ -396,45 +356,71 @@ inversionCheckboxes inversions =
         )
 
 
-keyCheckboxes : List Theory.Key -> Html Msg
-keyCheckboxes keys =
+selectKey :
+    Model
+    ->
+        { pitchClass : Theory.PitchClass
+        , majorKey : Theory.Key
+        , minorKey : Theory.Key
+        , bluesKey : Theory.Key
+        }
+    -> Html Msg
+selectKey model { pitchClass, majorKey, minorKey, bluesKey } =
+    let
+        active key =
+            List.member key model.whitelistedKeys
+    in
+    div [ class "flex pt-0" ]
+        [ p [ class "text-gray-500 text-center text-5xl flex-1 py-10" ] [ text (Theory.viewPitchClass pitchClass) ]
+        , UI.textToggleButton
+            { label = "major"
+            , handleClick = ToggleKey majorKey
+            , classes = [ "flex-1" ]
+            , toggled = active majorKey
+            }
+        , UI.textToggleButton
+            { label = "minor"
+            , handleClick = ToggleKey minorKey
+            , classes = [ "flex-1" ]
+            , toggled = active minorKey
+            }
+        , UI.textToggleButton
+            { label = "blues"
+            , handleClick = ToggleKey bluesKey
+            , classes = [ "flex-1" ]
+            , toggled = active bluesKey
+            }
+        ]
+
+
+keyCheckboxes : Model -> Html Msg
+keyCheckboxes model =
     div []
-        [ h2 [] [ text "Choose Key" ]
-        , button [ onClick SelectAllKeys ] [ text "Select all" ]
-        , button [ onClick DeselectAllKeys ] [ text "Deselect all" ]
+        [ h2 [ class "text-center py-10 text-5xl" ] [ text "Select Keys" ]
         , ul []
-            (Theory.allKeys
+            (Theory.allPitchClasses
                 |> List.map
-                    (\key ->
-                        li []
-                            [ label [] [ text (Theory.viewKey key) ]
-                            , input
-                                [ type_ "checkbox"
-                                , onClick (ToggleKey key)
-                                , checked (List.member key keys)
-                                ]
-                                []
-                            ]
+                    (\pitchClass ->
+                        selectKey model
+                            { pitchClass = pitchClass
+                            , majorKey = { pitchClass = pitchClass, mode = Theory.MajorMode }
+                            , minorKey = { pitchClass = pitchClass, mode = Theory.MinorMode }
+                            , bluesKey = { pitchClass = pitchClass, mode = Theory.BluesMode }
+                            }
                     )
             )
         ]
 
 
 displayChord :
-    { debug : Bool
-    , chord : Theory.Chord
+    { chord : Theory.Chord
     , firstNote : Theory.Note
     , lastNote : Theory.Note
     }
     -> Html Msg
-displayChord { debug, chord, firstNote, lastNote } =
+displayChord { chord, firstNote, lastNote } =
     div []
-        [ if debug then
-            ChordInspector.render chord
-
-          else
-            span [] []
-        , p [] [ text (Theory.viewChord chord) ]
+        [ p [] [ text (Theory.viewChord chord) ]
         , case Theory.notesForChord chord of
             Just x ->
                 Piano.render
@@ -448,57 +434,65 @@ displayChord { debug, chord, firstNote, lastNote } =
         ]
 
 
-view : Model -> Html Msg
-view model =
-    div []
+practiceModeButtons : Model -> Html Msg
+practiceModeButtons model =
+    div [ class "text-center" ]
+        [ h2 [ class "py-10 text-5xl" ] [ text "Practice Mode" ]
+        , div [ class "flex pb-6" ]
+            [ UI.simpleButton
+                { label = "Key"
+                , classes = [ "flex-1", "rounded-r-none" ]
+                , handleClick = SetPracticeMode KeyMode
+                , color =
+                    if model.practiceMode == KeyMode then
+                        UI.Primary
+
+                    else
+                        UI.Secondary
+                }
+            , UI.simpleButton
+                { label = "Fine Tune"
+                , handleClick = SetPracticeMode FineTuneMode
+                , classes = [ "flex-1", "rounded-l-none" ]
+                , color =
+                    if model.practiceMode == FineTuneMode then
+                        UI.Primary
+
+                    else
+                        UI.Secondary
+                }
+            ]
+        ]
+
+
+preferences : Model -> Html Msg
+preferences model =
+    div [ class "pt-10 pb-20 px-10" ]
         [ Tempo.render
             { tempo = model.tempo
-            , handleIncrease = IncreaseTempo
-            , handleDecrease = DecreaseTempo
             , handleInput = SetTempo
             }
-        , div []
-            [ h2 [] [ text "Practice Mode" ]
-            , input
-                [ type_ "radio"
-                , id "key-mode"
-                , name "key-mode"
-                , checked (model.practiceMode == KeyMode)
-                , onClick (SetPracticeMode KeyMode)
-                ]
-                []
-            , label [ for "key-mode" ] [ text "Key Mode" ]
-            , input
-                [ type_ "radio"
-                , id "fine-tune-mode"
-                , name "fine-tune-mode"
-                , checked (model.practiceMode == FineTuneMode)
-                , onClick (SetPracticeMode FineTuneMode)
-                ]
-                []
-            , label [ for "fine-tune-mode" ] [ text "Fine-tuning Mode" ]
-            ]
+        , practiceModeButtons model
         , case model.practiceMode of
             KeyMode ->
-                keyCheckboxes model.whitelistedKeys
+                keyCheckboxes model
 
             FineTuneMode ->
                 div []
-                    [ pitchClassCheckboxes model.whitelistedPitchClasses
-                    , inversionCheckboxes model.whitelistedInversions
+                    [ inversionCheckboxes model.whitelistedInversions
                     , chordTypeCheckboxes model.whitelistedChordTypes
                     ]
-        , playPause model
-        , if model.debug.enable then
-            debugger
+        ]
 
-          else
-            span [] []
+
+practice : Model -> Html Msg
+practice model =
+    div []
+        [ playPause model
         , case model.selectedChord of
             Just chord ->
                 displayChord
-                    { debug = model.debug.inspectChord
-                    , chord = chord
+                    { chord = chord
                     , firstNote = model.firstNote
                     , lastNote = model.lastNote
                     }
@@ -508,6 +502,16 @@ view model =
         ]
 
 
+view : Model -> Html Msg
+view model =
+    case model.view of
+        Preferences ->
+            preferences model
+
+        Practice ->
+            practice model
+
+
 {-| For now, I'm just dumping things onto the page to sketch ideas.
 -}
 main =
diff --git a/website/sandbox/chord-drill-sergeant/src/Tempo.elm b/website/sandbox/chord-drill-sergeant/src/Tempo.elm
index 270cc5bd6dc6..50485c4c0aba 100644
--- a/website/sandbox/chord-drill-sergeant/src/Tempo.elm
+++ b/website/sandbox/chord-drill-sergeant/src/Tempo.elm
@@ -3,25 +3,22 @@ module Tempo exposing (render)
 import Html exposing (..)
 import Html.Attributes exposing (..)
 import Html.Events exposing (..)
+import UI
 
 
 type alias Props msg =
     { tempo : Int
-    , handleIncrease : msg
-    , handleDecrease : msg
     , handleInput : String -> msg
     }
 
 
 render : Props msg -> Html msg
-render { tempo, handleIncrease, handleDecrease, handleInput } =
-    div []
-        [ p [] [ text (String.fromInt tempo ++ " BPM") ]
-        , button [ onClick handleDecrease ] [ text "Slower" ]
-        , input
-            [ onInput handleInput
-            , placeholder "Set tempo..."
-            ]
-            []
-        , button [ onClick handleIncrease ] [ text "Faster" ]
+render { tempo, handleInput } =
+    div [ class "text-center" ]
+        [ p [ class "text-5xl py-10" ] [ text (String.fromInt tempo ++ " BPM") ]
+        , UI.textField
+            { placeholderText = "Set tempo..."
+            , handleInput = handleInput
+            , classes = []
+            }
         ]
diff --git a/website/sandbox/chord-drill-sergeant/src/UI.elm b/website/sandbox/chord-drill-sergeant/src/UI.elm
new file mode 100644
index 000000000000..dff645f4796a
--- /dev/null
+++ b/website/sandbox/chord-drill-sergeant/src/UI.elm
@@ -0,0 +1,116 @@
+module UI exposing (..)
+
+import Html exposing (..)
+import Html.Attributes exposing (..)
+import Html.Events exposing (..)
+
+
+type Color
+    = Primary
+    | Secondary
+
+
+bgForColor : Color -> String
+bgForColor color =
+    case color of
+        Primary ->
+            "bg-gray-600"
+
+        Secondary ->
+            "bg-gray-300"
+
+
+textForColor : Color -> String
+textForColor color =
+    case color of
+        Primary ->
+            "text-white"
+
+        Secondary ->
+            "text-black"
+
+
+tw : List String -> String
+tw styles =
+    String.join " " styles
+
+
+simpleButton :
+    { label : String
+    , handleClick : msg
+    , color : Color
+    , classes : List String
+    }
+    -> Html msg
+simpleButton { label, handleClick, color, classes } =
+    let
+        buttonClasses =
+            [ bgForColor color
+            , textForColor color
+            , "py-10"
+            , "px-20"
+            , "text-5xl"
+            , "rounded-lg"
+            ]
+    in
+    button
+        [ class (tw <| List.concat [ buttonClasses, classes ])
+        , onClick handleClick
+        ]
+        [ text label ]
+
+
+textToggleButton :
+    { label : String
+    , handleClick : msg
+    , classes : List String
+    , toggled : Bool
+    }
+    -> Html msg
+textToggleButton { label, toggled, handleClick, classes } =
+    let
+        ( textColor, textTreatment ) =
+            if toggled then
+                ( "text-red-600", "underline" )
+
+            else
+                ( "text-black", "no-underline" )
+
+        buttonClasses =
+            [ textColor
+            , textTreatment
+            , "py-10"
+            , "px-10"
+            , "text-5xl"
+            ]
+    in
+    button
+        [ class (tw <| List.concat [ buttonClasses, classes ])
+        , onClick handleClick
+        ]
+        [ text label ]
+
+
+textField :
+    { placeholderText : String
+    , handleInput : String -> msg
+    , classes : List String
+    }
+    -> Html msg
+textField { placeholderText, handleInput, classes } =
+    let
+        inputClasses =
+            [ "text-5xl"
+            , "w-full"
+            , "py-10"
+            , "px-16"
+            , "border"
+            , "rounded-lg"
+            ]
+    in
+    input
+        [ class (tw <| List.concat [ inputClasses, classes ])
+        , onInput handleInput
+        , placeholder placeholderText
+        ]
+        []