Render a mobile-friendly piano
For now since I'm the only customer and I'm primarily making this for myself, I'm styling the app specifically for my Google Pixel 4. If I find this app useful, I will consider supporting other devices. I'm using the Icons that I bought when I purchased the "Refactoring UI" book. Other news: - I bought the domain learnpianochords.app! What's left: - Style the "fine tune" tab of the preferences view - Better support non-mobile devices like the browser and tablet devices - Deploy the application to learnpianochords.app - Redesign the "key" tab of the preferences view to sort the keys according to the circle of fifths - Dogfood - Simplify until I cannot simplify anymore
This commit is contained in:
parent
1d427c4921
commit
5ca0fa2fcd
5 changed files with 236 additions and 116 deletions
|
@ -10,6 +10,7 @@
|
||||||
"elm/core": "1.0.5",
|
"elm/core": "1.0.5",
|
||||||
"elm/html": "1.0.0",
|
"elm/html": "1.0.0",
|
||||||
"elm/random": "1.0.0",
|
"elm/random": "1.0.0",
|
||||||
|
"elm/svg": "1.0.1",
|
||||||
"elm/time": "1.0.0",
|
"elm/time": "1.0.0",
|
||||||
"elm-community/list-extra": "8.2.3",
|
"elm-community/list-extra": "8.2.3",
|
||||||
"elm-community/maybe-extra": "5.2.0",
|
"elm-community/maybe-extra": "5.2.0",
|
||||||
|
|
44
website/sandbox/chord-drill-sergeant/src/Icon.elm
Normal file
44
website/sandbox/chord-drill-sergeant/src/Icon.elm
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
module Icon exposing (..)
|
||||||
|
|
||||||
|
import Svg exposing (node, svg)
|
||||||
|
import Svg.Attributes exposing (..)
|
||||||
|
import UI
|
||||||
|
|
||||||
|
|
||||||
|
svgColor color =
|
||||||
|
let
|
||||||
|
classes =
|
||||||
|
case color of
|
||||||
|
UI.Primary ->
|
||||||
|
[ "text-gray-500", "fill-current" ]
|
||||||
|
|
||||||
|
UI.Secondary ->
|
||||||
|
[ "text-gray-300", "fill-current" ]
|
||||||
|
in
|
||||||
|
class <| String.join " " classes
|
||||||
|
|
||||||
|
|
||||||
|
cog =
|
||||||
|
svg [ class "icon-cog", viewBox "0 0 24 24", xmlLang "http://www.w3.org/2000/svg" ]
|
||||||
|
[ Svg.path
|
||||||
|
[ svgColor UI.Primary
|
||||||
|
, d "M6.8 3.45c.87-.52 1.82-.92 2.83-1.17a2.5 2.5 0 0 0 4.74 0c1.01.25 1.96.65 2.82 1.17a2.5 2.5 0 0 0 3.36 3.36c.52.86.92 1.8 1.17 2.82a2.5 2.5 0 0 0 0 4.74c-.25 1.01-.65 1.96-1.17 2.82a2.5 2.5 0 0 0-3.36 3.36c-.86.52-1.8.92-2.82 1.17a2.5 2.5 0 0 0-4.74 0c-1.01-.25-1.96-.65-2.82-1.17a2.5 2.5 0 0 0-3.36-3.36 9.94 9.94 0 0 1-1.17-2.82 2.5 2.5 0 0 0 0-4.74c.25-1.01.65-1.96 1.17-2.82a2.5 2.5 0 0 0 3.36-3.36zM12 16a4 4 0 1 0 0-8 4 4 0 0 0 0 8z"
|
||||||
|
, fill "red"
|
||||||
|
]
|
||||||
|
[]
|
||||||
|
, node "circle"
|
||||||
|
[ svgColor UI.Secondary, cx "12", cy "12", r "2" ]
|
||||||
|
[]
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
close =
|
||||||
|
svg [ class "icon-close", viewBox "0 0 24 24", xmlLang "http://www.w3.org/2000/svg" ]
|
||||||
|
[ Svg.path
|
||||||
|
[ svgColor UI.Primary
|
||||||
|
, d "M15.78 14.36a1 1 0 0 1-1.42 1.42l-2.82-2.83-2.83 2.83a1 1 0 1 1-1.42-1.42l2.83-2.82L7.3 8.7a1 1 0 0 1 1.42-1.42l2.83 2.83 2.82-2.83a1 1 0 0 1 1.42 1.42l-2.83 2.83 2.83 2.82z"
|
||||||
|
, fill "red"
|
||||||
|
, fillRule "evenodd"
|
||||||
|
]
|
||||||
|
[]
|
||||||
|
]
|
|
@ -4,6 +4,7 @@ import Browser
|
||||||
import Html exposing (..)
|
import Html exposing (..)
|
||||||
import Html.Attributes exposing (..)
|
import Html.Attributes exposing (..)
|
||||||
import Html.Events exposing (..)
|
import Html.Events exposing (..)
|
||||||
|
import Icon
|
||||||
import Piano
|
import Piano
|
||||||
import Random
|
import Random
|
||||||
import Random.List
|
import Random.List
|
||||||
|
@ -57,6 +58,7 @@ type Msg
|
||||||
| SetPracticeMode PracticeMode
|
| SetPracticeMode PracticeMode
|
||||||
| SelectAllKeys
|
| SelectAllKeys
|
||||||
| DeselectAllKeys
|
| DeselectAllKeys
|
||||||
|
| SetView View
|
||||||
|
|
||||||
|
|
||||||
{-| The amount by which we increase or decrease tempo.
|
{-| The amount by which we increase or decrease tempo.
|
||||||
|
@ -84,7 +86,7 @@ init : Model
|
||||||
init =
|
init =
|
||||||
let
|
let
|
||||||
( firstNote, lastNote ) =
|
( firstNote, lastNote ) =
|
||||||
( Theory.A1, Theory.C8 )
|
( Theory.C3, Theory.C6 )
|
||||||
|
|
||||||
inversions =
|
inversions =
|
||||||
Theory.allInversions
|
Theory.allInversions
|
||||||
|
@ -124,7 +126,7 @@ init =
|
||||||
, tempo = 30
|
, tempo = 30
|
||||||
, firstNote = firstNote
|
, firstNote = firstNote
|
||||||
, lastNote = lastNote
|
, lastNote = lastNote
|
||||||
, view = Preferences
|
, view = Practice
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -153,6 +155,13 @@ update msg model =
|
||||||
, Cmd.none
|
, Cmd.none
|
||||||
)
|
)
|
||||||
|
|
||||||
|
SetView x ->
|
||||||
|
( { model
|
||||||
|
| view = x
|
||||||
|
}
|
||||||
|
, Cmd.none
|
||||||
|
)
|
||||||
|
|
||||||
SelectAllKeys ->
|
SelectAllKeys ->
|
||||||
( { model
|
( { model
|
||||||
| whitelistedKeys = Theory.allKeys
|
| whitelistedKeys = Theory.allKeys
|
||||||
|
@ -412,28 +421,6 @@ keyCheckboxes model =
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
displayChord :
|
|
||||||
{ chord : Theory.Chord
|
|
||||||
, firstNote : Theory.Note
|
|
||||||
, lastNote : Theory.Note
|
|
||||||
}
|
|
||||||
-> Html Msg
|
|
||||||
displayChord { chord, firstNote, lastNote } =
|
|
||||||
div []
|
|
||||||
[ p [] [ text (Theory.viewChord chord) ]
|
|
||||||
, case Theory.notesForChord chord of
|
|
||||||
Just x ->
|
|
||||||
Piano.render
|
|
||||||
{ highlight = x
|
|
||||||
, start = firstNote
|
|
||||||
, end = lastNote
|
|
||||||
}
|
|
||||||
|
|
||||||
Nothing ->
|
|
||||||
p [] [ text "No chord to show" ]
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
practiceModeButtons : Model -> Html Msg
|
practiceModeButtons : Model -> Html Msg
|
||||||
practiceModeButtons model =
|
practiceModeButtons model =
|
||||||
div [ class "text-center" ]
|
div [ class "text-center" ]
|
||||||
|
@ -465,10 +452,29 @@ practiceModeButtons model =
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
openPreferences : Html Msg
|
||||||
|
openPreferences =
|
||||||
|
button
|
||||||
|
[ class "w-48 h-48 absolute left-0 top-0 z-20"
|
||||||
|
, onClick (SetView Preferences)
|
||||||
|
]
|
||||||
|
[ Icon.cog ]
|
||||||
|
|
||||||
|
|
||||||
|
closePreferences : Html Msg
|
||||||
|
closePreferences =
|
||||||
|
button
|
||||||
|
[ class "w-48 h-48 absolute right-0 top-0 z-10"
|
||||||
|
, onClick (SetView Practice)
|
||||||
|
]
|
||||||
|
[ Icon.close ]
|
||||||
|
|
||||||
|
|
||||||
preferences : Model -> Html Msg
|
preferences : Model -> Html Msg
|
||||||
preferences model =
|
preferences model =
|
||||||
div [ class "pt-10 pb-20 px-10" ]
|
div [ class "pt-10 pb-20 px-10" ]
|
||||||
[ Tempo.render
|
[ closePreferences
|
||||||
|
, Tempo.render
|
||||||
{ tempo = model.tempo
|
{ tempo = model.tempo
|
||||||
, handleInput = SetTempo
|
, handleInput = SetTempo
|
||||||
}
|
}
|
||||||
|
@ -487,18 +493,36 @@ preferences model =
|
||||||
|
|
||||||
practice : Model -> Html Msg
|
practice : Model -> Html Msg
|
||||||
practice model =
|
practice model =
|
||||||
div []
|
let
|
||||||
[ playPause model
|
classes =
|
||||||
, case model.selectedChord of
|
[ "bg-gray-600"
|
||||||
Just chord ->
|
, "h-screen"
|
||||||
displayChord
|
, "w-full"
|
||||||
{ chord = chord
|
, "absolute"
|
||||||
, firstNote = model.firstNote
|
, "z-10"
|
||||||
, lastNote = model.lastNote
|
, "text-6xl"
|
||||||
}
|
]
|
||||||
|
|
||||||
Nothing ->
|
( handleClick, extraClasses, buttonText ) =
|
||||||
p [] [ text "No chord to display" ]
|
if model.isPaused then
|
||||||
|
( Play, [ "opacity-50" ], "Press to resume" )
|
||||||
|
|
||||||
|
else
|
||||||
|
( Pause, [ "opacity-0" ], "" )
|
||||||
|
in
|
||||||
|
div []
|
||||||
|
[ button
|
||||||
|
[ [ classes, extraClasses ] |> List.concat |> UI.tw |> class
|
||||||
|
, onClick handleClick
|
||||||
|
]
|
||||||
|
[ text buttonText
|
||||||
|
]
|
||||||
|
, openPreferences
|
||||||
|
, Piano.render
|
||||||
|
{ highlight = model.selectedChord |> Maybe.andThen Theory.notesForChord |> Maybe.withDefault []
|
||||||
|
, start = model.firstNote
|
||||||
|
, end = model.lastNote
|
||||||
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,10 +8,18 @@ import List.Extra
|
||||||
import Theory
|
import Theory
|
||||||
|
|
||||||
|
|
||||||
|
{-| On mobile phones, the keyboard displays vertically.
|
||||||
|
-}
|
||||||
|
type Direction
|
||||||
|
= Horizontal
|
||||||
|
| Vertical
|
||||||
|
|
||||||
|
|
||||||
type alias KeyMarkup a =
|
type alias KeyMarkup a =
|
||||||
{ offset : Int
|
{ offset : Int
|
||||||
, isHighlit : Bool
|
, isHighlit : Bool
|
||||||
, note : Theory.Note
|
, note : Theory.Note
|
||||||
|
, direction : Direction
|
||||||
}
|
}
|
||||||
-> Html a
|
-> Html a
|
||||||
|
|
||||||
|
@ -32,121 +40,149 @@ pixelate x =
|
||||||
|
|
||||||
{-| Pixel width of the white keys.
|
{-| Pixel width of the white keys.
|
||||||
-}
|
-}
|
||||||
naturalWidth : Int
|
naturalWidth : Direction -> Int
|
||||||
naturalWidth =
|
naturalWidth direction =
|
||||||
|
case direction of
|
||||||
|
Vertical ->
|
||||||
|
-- Right now, I'm designing this specifically for my Google Pixel 4
|
||||||
|
-- phone, which has a screen width of 1080px.
|
||||||
|
1080
|
||||||
|
|
||||||
|
Horizontal ->
|
||||||
45
|
45
|
||||||
|
|
||||||
|
|
||||||
{-| Pixel height of the white keys.
|
{-| Pixel height of the white keys.
|
||||||
-}
|
-}
|
||||||
naturalHeight : Int
|
naturalHeight : Direction -> Int
|
||||||
naturalHeight =
|
naturalHeight direction =
|
||||||
|
case direction of
|
||||||
|
Vertical ->
|
||||||
|
-- Right now, I'm designing this specifically for my Google Pixel 4
|
||||||
|
-- phone, which has a screen height of 2280px. 2280 / 21
|
||||||
|
-- (i.e. no. natural keys) ~= 108
|
||||||
|
108
|
||||||
|
|
||||||
|
Horizontal ->
|
||||||
250
|
250
|
||||||
|
|
||||||
|
|
||||||
{-| Pixel width of the black keys.
|
{-| Pixel width of the black keys.
|
||||||
-}
|
-}
|
||||||
accidentalWidth : Int
|
accidentalWidth : Direction -> Int
|
||||||
accidentalWidth =
|
accidentalWidth direction =
|
||||||
round (toFloat naturalWidth * 0.4)
|
case direction of
|
||||||
|
Vertical ->
|
||||||
|
round (toFloat (naturalWidth direction) * 0.6)
|
||||||
|
|
||||||
|
Horizontal ->
|
||||||
|
round (toFloat (naturalWidth direction) * 0.4)
|
||||||
|
|
||||||
|
|
||||||
{-| Pixel height of the black keys.
|
{-| Pixel height of the black keys.
|
||||||
-}
|
-}
|
||||||
accidentalHeight : Int
|
accidentalHeight : Direction -> Int
|
||||||
accidentalHeight =
|
accidentalHeight direction =
|
||||||
round (toFloat naturalHeight * 0.63)
|
case direction of
|
||||||
|
Vertical ->
|
||||||
|
round (toFloat (naturalHeight direction) * 0.63)
|
||||||
|
|
||||||
|
Horizontal ->
|
||||||
|
round (toFloat (naturalHeight direction) * 0.63)
|
||||||
|
|
||||||
|
|
||||||
{-| These are the white keys on most modern pianos.
|
{-| Return the markup for either a white or a black key.
|
||||||
-}
|
-}
|
||||||
natural : KeyMarkup a
|
pianoKey : KeyMarkup a
|
||||||
natural { offset, isHighlit, note } =
|
pianoKey { offset, isHighlit, note, direction } =
|
||||||
|
let
|
||||||
|
sharedClasses =
|
||||||
|
[ "box-border" ]
|
||||||
|
|
||||||
|
{ keyWidth, keyHeight, keyColor, offsetEdge, extraClasses } =
|
||||||
|
case ( Theory.keyClass note, direction ) of
|
||||||
|
( Theory.Natural, Vertical ) ->
|
||||||
|
{ keyWidth = naturalWidth Vertical
|
||||||
|
, keyHeight = naturalHeight Vertical
|
||||||
|
, keyColor = "white"
|
||||||
|
, offsetEdge = "top"
|
||||||
|
, extraClasses = []
|
||||||
|
}
|
||||||
|
|
||||||
|
( Theory.Natural, Horizontal ) ->
|
||||||
|
{ keyWidth = naturalWidth Horizontal
|
||||||
|
, keyHeight = naturalHeight Horizontal
|
||||||
|
, keyColor = "white"
|
||||||
|
, offsetEdge = "left"
|
||||||
|
, extraClasses = []
|
||||||
|
}
|
||||||
|
|
||||||
|
( Theory.Accidental, Vertical ) ->
|
||||||
|
{ keyWidth = accidentalWidth Vertical
|
||||||
|
, keyHeight = accidentalHeight Vertical
|
||||||
|
, keyColor = "black"
|
||||||
|
, offsetEdge = "top"
|
||||||
|
, extraClasses = [ "z-10" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
( Theory.Accidental, Horizontal ) ->
|
||||||
|
{ keyWidth = accidentalWidth Horizontal
|
||||||
|
, keyHeight = accidentalHeight Horizontal
|
||||||
|
, keyColor = "black"
|
||||||
|
, offsetEdge = "left"
|
||||||
|
, extraClasses = [ "z-10" ]
|
||||||
|
}
|
||||||
|
in
|
||||||
div
|
div
|
||||||
[ style "background-color"
|
[ style "background-color"
|
||||||
(if isHighlit then
|
(if isHighlit then
|
||||||
"red"
|
"red"
|
||||||
|
|
||||||
else
|
else
|
||||||
"white"
|
keyColor
|
||||||
)
|
)
|
||||||
, style "border-right" "1px solid black"
|
|
||||||
, style "border-top" "1px solid black"
|
, style "border-top" "1px solid black"
|
||||||
, style "border-bottom" "1px solid black"
|
, style "border-bottom" "1px solid black"
|
||||||
, style "width" (pixelate naturalWidth)
|
|
||||||
, style "height" (pixelate naturalHeight)
|
|
||||||
, style "position" "absolute"
|
|
||||||
, style "left" (String.fromInt offset ++ "px")
|
|
||||||
]
|
|
||||||
[]
|
|
||||||
|
|
||||||
|
|
||||||
{-| These are the black keys on most modern pianos.
|
|
||||||
-}
|
|
||||||
accidental : KeyMarkup a
|
|
||||||
accidental { offset, isHighlit, note } =
|
|
||||||
div
|
|
||||||
[ style "background-color"
|
|
||||||
(if isHighlit then
|
|
||||||
"red"
|
|
||||||
|
|
||||||
else
|
|
||||||
"black"
|
|
||||||
)
|
|
||||||
, style "border-top" "1px solid black"
|
|
||||||
, style "border-left" "1px solid black"
|
, style "border-left" "1px solid black"
|
||||||
, style "border-right" "1px solid black"
|
, style "border-right" "1px solid black"
|
||||||
, style "border-bottom" "1px solid black"
|
, style "width" (pixelate keyWidth)
|
||||||
, style "width" (pixelate accidentalWidth)
|
, style "height" (pixelate keyHeight)
|
||||||
, style "height" (pixelate accidentalHeight)
|
|
||||||
, style "position" "absolute"
|
, style "position" "absolute"
|
||||||
, style "left" (String.fromInt offset ++ "px")
|
, style offsetEdge (String.fromInt offset ++ "px")
|
||||||
, style "z-index" "1"
|
, class <| String.join " " (List.concat [ sharedClasses, extraClasses ])
|
||||||
]
|
]
|
||||||
[]
|
[]
|
||||||
|
|
||||||
|
|
||||||
makeKey : List Theory.Note -> Theory.Note -> (Int -> Html a)
|
{-| A section of the piano consisting of all twelve notes.
|
||||||
makeKey highlight note =
|
|
||||||
if Theory.isNatural note then
|
|
||||||
\x ->
|
|
||||||
natural
|
|
||||||
{ offset = x
|
|
||||||
, isHighlit = List.member note highlight
|
|
||||||
, note = note
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
\x ->
|
|
||||||
accidental
|
|
||||||
{ offset = x
|
|
||||||
, isHighlit = List.member note highlight
|
|
||||||
, note = note
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
{-| A section of the piano consisting of all twelve notes. The name octave
|
|
||||||
implies eight notes, which most scales (not the blues scale) honor.
|
|
||||||
-}
|
-}
|
||||||
octave : Theory.Note -> Theory.Note -> List Theory.Note -> List (Html a)
|
keys : Direction -> Theory.Note -> Theory.Note -> List Theory.Note -> List (Html a)
|
||||||
octave start end highlight =
|
keys direction start end highlight =
|
||||||
let
|
let
|
||||||
isHighlit note =
|
isHighlit note =
|
||||||
List.member note highlight
|
List.member note highlight
|
||||||
|
|
||||||
spacing prevOffset prev curr =
|
spacing prevOffset prev curr =
|
||||||
case ( Theory.keyClass prev, Theory.keyClass curr ) of
|
case ( Theory.keyClass prev, Theory.keyClass curr, direction ) of
|
||||||
( Theory.Natural, Theory.Accidental ) ->
|
-- Horizontal
|
||||||
-- idk this calculation yet
|
( Theory.Natural, Theory.Accidental, Horizontal ) ->
|
||||||
prevOffset + naturalWidth - round (toFloat accidentalWidth / 2)
|
prevOffset + naturalWidth direction - round (toFloat (accidentalWidth direction) / 2)
|
||||||
|
|
||||||
( Theory.Accidental, Theory.Natural ) ->
|
( Theory.Accidental, Theory.Natural, Horizontal ) ->
|
||||||
-- accidentalWidth / 2
|
prevOffset + round (toFloat (accidentalWidth direction) / 2)
|
||||||
prevOffset + round (toFloat accidentalWidth / 2)
|
|
||||||
|
|
||||||
( Theory.Natural, Theory.Natural ) ->
|
( Theory.Natural, Theory.Natural, Horizontal ) ->
|
||||||
-- naturalWidth
|
prevOffset + naturalWidth direction
|
||||||
prevOffset + naturalWidth
|
|
||||||
|
-- Vertical
|
||||||
|
( Theory.Natural, Theory.Accidental, Vertical ) ->
|
||||||
|
prevOffset + naturalHeight direction - round (toFloat (accidentalHeight direction) / 2)
|
||||||
|
|
||||||
|
( Theory.Accidental, Theory.Natural, Vertical ) ->
|
||||||
|
prevOffset + round (toFloat (accidentalHeight direction) / 2)
|
||||||
|
|
||||||
|
( Theory.Natural, Theory.Natural, Vertical ) ->
|
||||||
|
prevOffset + naturalHeight direction
|
||||||
|
|
||||||
-- This pattern should never hit.
|
-- This pattern should never hit.
|
||||||
_ ->
|
_ ->
|
||||||
|
@ -158,7 +194,16 @@ octave start end highlight =
|
||||||
(\curr ( prevOffset, prev, result ) ->
|
(\curr ( prevOffset, prev, result ) ->
|
||||||
case ( prevOffset, prev ) of
|
case ( prevOffset, prev ) of
|
||||||
( Nothing, Nothing ) ->
|
( Nothing, Nothing ) ->
|
||||||
( Just 0, Just curr, makeKey highlight curr 0 :: result )
|
( Just 0
|
||||||
|
, Just curr
|
||||||
|
, pianoKey
|
||||||
|
{ offset = 0
|
||||||
|
, isHighlit = List.member curr highlight
|
||||||
|
, note = curr
|
||||||
|
, direction = direction
|
||||||
|
}
|
||||||
|
:: result
|
||||||
|
)
|
||||||
|
|
||||||
( Just po, Just p ) ->
|
( Just po, Just p ) ->
|
||||||
let
|
let
|
||||||
|
@ -167,7 +212,13 @@ octave start end highlight =
|
||||||
in
|
in
|
||||||
( Just offset
|
( Just offset
|
||||||
, Just curr
|
, Just curr
|
||||||
, makeKey highlight curr offset :: result
|
, pianoKey
|
||||||
|
{ offset = offset
|
||||||
|
, isHighlit = List.member curr highlight
|
||||||
|
, note = curr
|
||||||
|
, direction = direction
|
||||||
|
}
|
||||||
|
:: result
|
||||||
)
|
)
|
||||||
|
|
||||||
-- This pattern should never hit.
|
-- This pattern should never hit.
|
||||||
|
@ -184,4 +235,4 @@ octave start end highlight =
|
||||||
render : Props -> Html a
|
render : Props -> Html a
|
||||||
render { highlight, start, end } =
|
render { highlight, start, end } =
|
||||||
div [ style "display" "flex" ]
|
div [ style "display" "flex" ]
|
||||||
(octave start end highlight |> List.reverse |> List.repeat 1 |> List.concat)
|
(keys Vertical start end highlight |> List.reverse |> List.repeat 1 |> List.concat)
|
||||||
|
|
|
@ -79,7 +79,7 @@ textToggleButton { label, toggled, handleClick, classes } =
|
||||||
buttonClasses =
|
buttonClasses =
|
||||||
[ textColor
|
[ textColor
|
||||||
, textTreatment
|
, textTreatment
|
||||||
, "py-10"
|
, "py-8"
|
||||||
, "px-10"
|
, "px-10"
|
||||||
, "text-5xl"
|
, "text-5xl"
|
||||||
]
|
]
|
||||||
|
|
Loading…
Reference in a new issue