Простое приложение, Эльм, используя стиль-элементы


Я сделал простое приложение для возвращения дозы препаратов для лечения конкретной медицинской проблемы на различных этапах лечения. Я хотел бы советы о том, как лучше организовать код и минимизации ненужных проблем с производительностью. На приложение этого простого, это вряд ли будет проблемой, но я хотел бы, чтобы распознавать неэффективные модели я использую, прежде чем перейти к более сложным проектам.

Главная.Эльм:

module Main exposing (..)

import Html
import Element exposing (..)
import Element.Events exposing (onBlur, onClick)
import Element.Attributes exposing (..)
import MyStyle exposing (..)


type alias Menu =
    { label : String
    , group : Group
    , choices : List Choice
    }


type alias Choice =
    { label : String
    , item : Item
    }


type Item
    = Diazepam
    | Lorazepam
    | Midazolam
    | Phenytoin
    | Fosphenytoin
    | Valproate
    | Levetiracetam
    | Phenobarbital
    | MidazolamSedation
    | Propofol
    | Pentobarbital
    | PhenobarbitalSedation
    | Topiramate
    | Zonisamide
    | Lacosamide
    | Ketamine
    | Methylprednisolone
    | IVIG
    | NoneChosen


toString : Item -> String
toString item =
    case item of
        Diazepam ->
            "Diazepam"

        Lorazepam ->
            "Lorazepam"

        Midazolam ->
            "Midazolam"

        Phenytoin ->
            "Phenytoin"

        Fosphenytoin ->
            "Fosphenytoin"

        Valproate ->
            "Valproate"

        Levetiracetam ->
            "Levetiracetam"

        Phenobarbital ->
            "Phenobarbital"

        MidazolamSedation ->
            "Midazolam gtt"

        Propofol ->
            "Propofol"

        Pentobarbital ->
            "Pentobarbital"

        PhenobarbitalSedation ->
            "Phenobarbital gtt"

        Topiramate ->
            "Topiramate"

        Zonisamide ->
            "Zonisamide"

        Lacosamide ->
            "Lacosamide"

        Ketamine ->
            "Ketamine"

        Methylprednisolone ->
            "Methylprednisolone"

        IVIG ->
            "IVIG"

        NoneChosen ->
            "No Medication Chosen"


firstLineMenu : Menu
firstLineMenu =
    { label = "First line agents"
    , group = FirstLine
    , choices =
        [ { label = "Diazepam"
          , item = Diazepam
          }
        , { label = "Lorazepam"
          , item = Lorazepam
          }
        , { label = "Midazolam"
          , item = Midazolam
          }
        ]
    }


secondLineMenu : Menu
secondLineMenu =
    { label = "Second line agents"
    , group = SecondLine
    , choices =
        [ { label = "Fosphenytoin"
          , item = Fosphenytoin
          }
        , { label = "Phenytoin"
          , item = Phenytoin
          }
        , { label = "Levetiracetam"
          , item = Levetiracetam
          }
        , { label = "Valproate"
          , item = Valproate
          }
        , { label = "Phenobarbital"
          , item = Phenobarbital
          }
        ]
    }


thirdLineMenu : Menu
thirdLineMenu =
    { label = "Third line agents"
    , group = ThirdLine
    , choices =
        [ { label = "Midazolam"
          , item = MidazolamSedation
          }
        , { label = "Propofol"
          , item = Propofol
          }
        , { label = "Pentobarbital"
          , item = Pentobarbital
          }
        , { label = "Phenobarbital"
          , item = PhenobarbitalSedation
          }
        ]
    }


fourthLineMenu : Menu
fourthLineMenu =
    { label = "Fourth line agents"
    , group = FourthLine
    , choices =
        [ { label = "Topiramate"
          , item = Topiramate
          }
        , { label = "Zonisamide"
          , item = Zonisamide
          }
        , { label = "Lacosamide"
          , item = Lacosamide
          }
        , { label = "Ketamine"
          , item = Ketamine
          }
        , { label = "Methylprednisolone"
          , item = Methylprednisolone
          }
        , { label = "IVIG"
          , item = IVIG
          }
        ]
    }


type WtUnit
    = Lb
    | Kg
    | NotIndicated


type alias Model =
    { firstLine : Item
    , secondLine : Item
    , thirdLine : Item
    , fourthLine : Item
    , activeMenu : Group
    , lastGroup : Group
    , lastSelection : Item
    , activeMedDose : Maybe String
    }


model : Model
model =
    { firstLine = NoneChosen
    , secondLine = NoneChosen
    , thirdLine = NoneChosen
    , fourthLine = NoneChosen
    , activeMenu = NoGroup
    , lastGroup = NoGroup
    , lastSelection = NoneChosen
    , activeMedDose = Nothing
    }


type Group
    = FirstLine
    | SecondLine
    | ThirdLine
    | FourthLine
    | NoGroup


menuChoice : Model -> Choice -> Element MyStyles variation Msg
menuChoice model choice =
    case model.activeMenu of
        FirstLine ->
            if
                choice.item
                    == model.firstLine
            then
                el Selected [ onClick (SelectChoice choice), padding 6, paddingLeft 12, width (px 178) ] (text (choice.label))
            else
                el Selection [ onClick (SelectChoice choice), padding 6, paddingLeft 12, width (px 178) ] (text choice.label)

        SecondLine ->
            if
                choice.item
                    == model.secondLine
            then
                el Selected [ onClick (SelectChoice choice), padding 6, paddingLeft 12, width (px 178) ] (text (choice.label))
            else
                el Selection [ onClick (SelectChoice choice), padding 6, paddingLeft 12, width (px 178) ] (text choice.label)

        ThirdLine ->
            if
                choice.item
                    == model.thirdLine
            then
                el Selected [ onClick (SelectChoice choice), padding 6, paddingLeft 12, width (px 178) ] (text (choice.label))
            else
                el Selection [ onClick (SelectChoice choice), padding 6, paddingLeft 12, width (px 178) ] (text choice.label)

        FourthLine ->
            if
                choice.item
                    == model.fourthLine
            then
                el Selected [ onClick (SelectChoice choice), padding 6, paddingLeft 12, width (px 178) ] (text (choice.label))
            else
                el Selection [ onClick (SelectChoice choice), padding 6, paddingLeft 12, width (px 178) ] (text choice.label)

        _ ->
            el None [] empty


prepend : List a -> List a -> List a
prepend listA listB =
    List.append listB listA


menuDown : Model -> Menu -> Element MyStyles variation Msg
menuDown model menu =
    wrappedColumn Content
        [ alignLeft, alignTop, padding 10, paddingTop 0, width (px 300), height (px 60) ]
        (if menu.group == model.activeMenu then
            (case model.activeMenu of
                FirstLine ->
                    (List.append
                        [ row ActiveMenuHeader [ verticalCenter, alignLeft, onClick (CloseMenu), padding 8, paddingLeft 16, width (px 290) ] [ text menu.label ] ]
                        [ column ActiveMenuTop
                            [ center, paddingTop 20, width (px 180), height (px 239), alignTop, inlineStyle [ ( "z-index", "999" ) ] ]
                            (List.map
                                (\choice ->
                                    menuChoice model choice
                                )
                                menu.choices
                            )
                        ]
                    )

                SecondLine ->
                    (List.append
                        [ row ActiveMenuHeader [ verticalCenter, alignLeft, onClick (CloseMenu), padding 8, paddingLeft 16, width (px 290) ] [ text menu.label ] ]
                        [ column ActiveMenu
                            [ center, moveUp 60, paddingTop 20, width (px 180), height (px 239), alignTop, inlineStyle [ ( "z-index", "999" ) ] ]
                            (List.map
                                (\choice ->
                                    menuChoice model choice
                                )
                                menu.choices
                            )
                        ]
                    )

                ThirdLine ->
                    (List.append
                        [ row ActiveMenuHeader [ verticalCenter, alignLeft, onClick (CloseMenu), padding 8, paddingLeft 16, width (px 290) ] [ text menu.label ] ]
                        [ column ActiveMenu
                            [ center, moveUp 120, paddingTop 20, width (px 180), height (px 239), alignTop, inlineStyle [ ( "z-index", "999" ) ] ]
                            (List.map
                                (\choice ->
                                    menuChoice model choice
                                )
                                menu.choices
                            )
                        ]
                    )

                FourthLine ->
                    (List.append
                        [ row ActiveMenuHeader [ verticalCenter, alignLeft, onClick (CloseMenu), padding 8, paddingLeft 16, width (px 290) ] [ text menu.label ] ]
                        [ column ActiveMenuBottom
                            [ center, moveUp 180, paddingTop 20, width (px 180), height (px 239), alignTop, inlineStyle [ ( "z-index", "999" ) ] ]
                            (List.map
                                (\choice ->
                                    menuChoice model choice
                                )
                                menu.choices
                            )
                        ]
                    )

                _ ->
                    [ el Header [] empty ]
            )
         else
            [ row Header [ verticalCenter, alignLeft, onClick (OpenMenu menu), padding 8, paddingLeft 16, width fill ] [ text menu.label ] ]
        )


menuUp : Model -> Menu -> Element MyStyles variation Msg
menuUp model menu =
    row None
        [ alignBottom ]
        [ column Content
            []
            (if menu.group == model.activeMenu then
                prepend [ el Header [ onClick (CloseMenu) ] (text menu.label) ]
                    (List.map
                        (\choice ->
                            menuChoice model choice
                        )
                        menu.choices
                    )
             else
                [ el Header [ onClick (OpenMenu menu) ] (text menu.label) ]
            )
        ]



-- UPDATE --


update : Msg -> Model -> Model
update msg model =
    case msg of
        CloseMenu ->
            { model | activeMenu = NoGroup }

        OpenMenu menu ->
            { model | activeMenu = menu.group }

        SelectChoice choice ->
            markSelected model choice

        NoOp ->
            model


type Msg
    = CloseMenu
    | OpenMenu Menu
    | SelectChoice Choice
    | NoOp


updateActiveDose model selection =
    Just (dosing selection.item)


markSelected : Model -> Choice -> Model
markSelected model selection =
    case model.activeMenu of
        FirstLine ->
            { model
                | firstLine = selection.item
                , activeMenu = NoGroup
                , lastSelection = selection.item
                , activeMedDose = updateActiveDose model selection
                , lastGroup = model.activeMenu
            }

        SecondLine ->
            { model
                | secondLine = selection.item
                , activeMenu = NoGroup
                , lastSelection = selection.item
                , activeMedDose = updateActiveDose model selection
                , lastGroup = model.activeMenu
            }

        ThirdLine ->
            { model
                | thirdLine = selection.item
                , activeMenu = NoGroup
                , lastSelection = selection.item
                , activeMedDose = updateActiveDose model selection
                , lastGroup = model.activeMenu
            }

        FourthLine ->
            { model
                | fourthLine = selection.item
                , activeMenu = NoGroup
                , lastSelection = selection.item
                , activeMedDose = updateActiveDose model selection
                , lastGroup = model.activeMenu
            }

        _ ->
            model


dosing : Item -> String
dosing drug =
    case drug of
        Lorazepam ->
            "2-4 mg iv q5 minutes to maximum of 0.1 mg/kg"

        Diazepam ->
            "5 mg iv q10 minutes to maximum of 30 mg OR 20 mg given IR"

        Midazolam ->
            "10 mg im if iv access not immediately available"

        Fosphenytoin ->
            "20 mg/kg PE (phenytoin equivalents) iv administered at 150 mg/min with cardiac and BP monitoring"

        Phenytoin ->
            "20 mg/kg iv administered at 50 mg/min with cardiac and BP monitoring"

        Valproate ->
            "30 mg/kg iv administered over 10 minutes (caution if surgical or hemorrhagic case due to platelet effects)"

        Levetiracetam ->
            "2000 - 4000 mg iv at 500 mg/min"

        Phenobarbital ->
            "20 mg/kg iv administered at 50-100 mg/min"

        MidazolamSedation ->
            "0.1 mg/kg/hr initial dose titrated to sedation to max of 2.9 mg/kg per hour"

        Propofol ->
            "1-2 mg/kg iv load with infusion rate of 33 mcg/kg/min (1.98 mg/kg/hr) titrated to sedation or max of 250 mcg/kg/min (15 mg/kg/hr)"

        Pentobarbital ->
            "Load 15 mg/kg at 50 mg/min and start infusion with rate of 1 mg/kg/hr titrated to suppression or max of 5 mg/kg/hr"

        PhenobarbitalSedation ->
            "Load 15 mg/kg with 50-100mg iv TID maintenance"

        Topiramate ->
            "200-400 mg po or per ng BID titrated daily up to 1600 mg/day (risk of renal calculi)"

        Zonisamide ->
            "100 mg po or per ng daily titrated daily up to 400 mg/day (risk of renal calculi)"

        Lacosamide ->
            "100mg iv BID titrated up to 400mg/day (potential PR prolongation, cardiac arrhythmias)"

        Ketamine ->
            "Load 2 mg/kg bolus then 1 mg/kg/hr titrated to seizure freedom or max of 5 mg/kg/hr"

        Methylprednisolone ->
            "1000mg iv daily for five days"

        IVIG ->
            "0.4 grams/kg daily for 5 days"

        NoneChosen ->
            "None Selected"


view : Model -> Html.Html Msg
view model =
    Element.viewport stylesheet <|
        column Content
            [ width fill, height fill, center ]
            [ column None
                [ paddingTop 20, width fill, center ]
                [ menuDown model firstLineMenu
                , menuDown model secondLineMenu
                , menuDown model thirdLineMenu
                , menuDown model fourthLineMenu
                ]
            , column None
                [ width fill, padding 10, paddingTop 5, center ]
                (case model.lastGroup of
                    FirstLine ->
                        [ paragraph Header
                            [ padding 10, paddingBottom 5, width content, width (px 280) ]
                            [ text "Treating stage 1 of status epilepticus" ]
                        , paragraph Content
                            [ padding 10, paddingTop 5, width (px 280), height content ]
                            [ text "Seizure has lasted 5 minutes or more and/or multiple discrete seizures without clinical recovery between events." ]
                        ]

                    SecondLine ->
                        [ paragraph Header
                            [ padding 10, paddingBottom 5, width content, width (px 280) ]
                            [ text "Treating stage 2 of status epilepticus" ]
                        , paragraph Content
                            [ padding 10, paddingTop 5, width (px 280), height content ]
                            [ text "Seizures continue despite adequate benzodiazepine administration. In practice this stage and stage 1 are typically concurrent." ]
                        ]

                    ThirdLine ->
                        [ paragraph Header
                            [ padding 10, paddingBottom 5, width content, width (px 280) ]
                            [ text "Treating stage 3 of status epilepticus" ]
                        , paragraph Content
                            [ padding 10, paddingTop 5, width (px 280), height content ]
                            [ text "Refractory status epilepticus. Sedation with continuous EEG monitoring. Goal is burst-suppression with interburst intervals of ~10 seconds." ]
                        ]

                    FourthLine ->
                        [ paragraph Header
                            [ padding 10, paddingBottom 5, height content, width (px 280) ]
                            [ text "Treating stage 4 of status epilepticus" ]
                        , paragraph Content
                            [ padding 10, paddingTop 5, width (px 280), height content ]
                            [ text "Super refractory status epilepticus.  Little evidence to guide choice of agent.  Prognosis generally guarded." ]
                        ]

                    _ ->
                        [ empty ]
                )
            , (case model.activeMedDose of
                Nothing ->
                    el None
                        [ hidden ]
                        empty

                Just dose ->
                    paragraph Content
                        [ padding 10, onClick CloseMenu, width (px 280), height content ]
                        [ text
                            ("Dose for " ++ (toString model.lastSelection) ++ " is: " ++ dose)
                        ]
              )
            ]


main =
    Html.beginnerProgram
        { model = model
        , update = update
        , view = view
        }

И mystyle может.Эльм импортируется:

module MyStyle exposing (..)

import Color
import Style
import Style.Font as Font
import Style.Color as Color
import Style.Border as Border


type MyStyles
    = Header
    | SubHead
    | Content
    | Selection
    | Selected
    | Alerts
    | ActiveMenu
    | ActiveMenuTop
    | ActiveMenuBottom
    | ActiveMenuHeader
    | None


type MyColors
    = Primary
    | DarkPrimary
    | LightPrimary
    | Secondary
    | DarkSecondary
    | LightSecondary
    | Alert
    | Highlight
    | White
    | Black


type MyFonts
    = Headline
    | PrimarySans
    | SecondarySans
    | PrimarySerif
    | SecondarySerif
    | Fallback


fontStack : MyFonts -> Style.Font
fontStack font =
    case font of
        Headline ->
            Font.importUrl { url = "https://fonts.googleapis.com/css?family=Dosis", name = "dosis" }

        PrimarySans ->
            Font.importUrl { url = "https://fonts.googleapis.com/css?family=Lato", name = "lato" }

        SecondarySans ->
            Font.sansSerif

        PrimarySerif ->
            Font.importUrl { url = "https://fonts.googleapis.com/css?family=Esteban", name = "esteban" }

        SecondarySerif ->
            Font.serif

        Fallback ->
            Font.sansSerif


colorPalette : MyColors -> Color.Color
colorPalette mycolor =
    case mycolor of
        DarkPrimary ->
            Color.rgb 34 32 32

        LightPrimary ->
            Color.rgb 142 129 129

        Primary ->
            Color.rgb 53 42 42

        DarkSecondary ->
            Color.rgb 96 125 139

        LightSecondary ->
            Color.rgb 220 232 243

        Secondary ->
            Color.rgb 194 205 214

        Highlight ->
            Color.rgb 218 247 166

        Alert ->
            Color.rgb 232 53 53

        White ->
            Color.rgb 255 255 255

        Black ->
            Color.rgb 0 0 0


stylesheet =
    Style.styleSheet
        [ Style.style Header
            [ Color.background (colorPalette Primary)
            , Color.text (colorPalette LightSecondary)
            , Border.rounded 25
            , Border.solid
            , Font.size 36
            , Font.typeface
                [ fontStack Headline
                , fontStack Fallback
                ]
            ]
        , Style.style ActiveMenuHeader
            [ Color.background (colorPalette Primary)
            , Color.text (colorPalette Highlight)
            , Border.roundTopLeft 25
            , Border.roundBottomLeft 25
            , Font.size 36
            , Font.typeface
                [ fontStack Headline
                , fontStack Fallback
                ]
            ]
        , Style.style ActiveMenu
            [ Color.background (colorPalette Primary)
            , Color.text (colorPalette LightSecondary)
            , Border.rounded 25
            ]
        , Style.style ActiveMenuTop
            [ Color.background (colorPalette Primary)
            , Color.text (colorPalette LightSecondary)
            , Border.rounded 25
            , Border.roundTopLeft 0
            ]
        , Style.style ActiveMenuBottom
            [ Color.background (colorPalette Primary)
            , Color.text (colorPalette LightSecondary)
            , Border.rounded 25
            , Border.roundBottomLeft 0
            ]
        , Style.style SubHead
            [ Color.text (colorPalette LightSecondary)
            , Font.size 28
            , Font.typeface
            ]
        , Style.style Alerts
            [ Color.background (colorPalette Alert)
            , Color.text (colorPalette DarkSecondary)
            ]
        ]
      [ fontStack PrimarySans
                , fontStack Fallback
                ]
            ]
        , Style.style Content
            [ Color.background (colorPalette LightSecondary)
            , Color.text (colorPalette Primary)
            , Font.size 18
            , Font.typeface
                [ fontStack PrimarySans
                , fontStack Fallback
                ]
            ]
        , Style.style Selection
            [ Color.background (colorPalette Primary)
            , Color.text (colorPalette LightSecondary)
            , Font.size 17
            , Style.hover
                [ Color.background (colorPalette Highlight)
                , Color.text (colorPalette Primary)
                ]
            ]
        , Style.style Selected
            [ Color.background (colorPalette Primary)
            , Color.text (colorPalette Highlight)
            , Font.size 17
            , Style.hover
                [ Color.background (colorPalette Highlight)
                , Color.text (colorPalette Primary)
                ]
            ]
        , Style.style Alerts
            [ Color.background (colorPalette Alert)
            , Color.text (colorPalette DarkSecondary)
            ]
        ]


161
1
elm
задан 2 апреля 2018 в 03:04 Источник Поделиться
Комментарии