mirror of
https://github.com/Orasund/elm-ui-widgets.git
synced 2024-11-26 15:43:29 +03:00
Last touches
This commit is contained in:
parent
a5d03e6d26
commit
3a7eaff6c6
@ -1,9 +1,9 @@
|
|||||||
module Component exposing (Model,Msg(..),init,update,view)
|
module Component exposing (Model, Msg(..), init, update, view)
|
||||||
|
|
||||||
import Browser
|
import Browser
|
||||||
import Element exposing (Element,Color)
|
import Element exposing (Color, Element)
|
||||||
import Element.Input as Input
|
|
||||||
import Element.Background as Background
|
import Element.Background as Background
|
||||||
|
import Element.Input as Input
|
||||||
import Framework
|
import Framework
|
||||||
import Framework.Button as Button
|
import Framework.Button as Button
|
||||||
import Framework.Card as Card
|
import Framework.Card as Card
|
||||||
@ -13,63 +13,64 @@ import Framework.Group as Group
|
|||||||
import Framework.Heading as Heading
|
import Framework.Heading as Heading
|
||||||
import Framework.Input as Input
|
import Framework.Input as Input
|
||||||
import Framework.Tag as Tag
|
import Framework.Tag as Tag
|
||||||
|
import Heroicons.Solid as Heroicons
|
||||||
import Html exposing (Html)
|
import Html exposing (Html)
|
||||||
import Html.Attributes as Attributes
|
import Html.Attributes as Attributes
|
||||||
import Set exposing (Set)
|
import Set exposing (Set)
|
||||||
|
import Time
|
||||||
import Widget
|
import Widget
|
||||||
import Widget.FilterSelect as FilterSelect
|
import Widget.FilterSelect as FilterSelect
|
||||||
import Widget.ScrollingNav as ScrollingNav
|
import Widget.ScrollingNav as ScrollingNav
|
||||||
import Widget.ValidatedInput as ValidatedInput
|
|
||||||
import Widget.Snackbar as Snackbar
|
import Widget.Snackbar as Snackbar
|
||||||
import Time
|
import Widget.ValidatedInput as ValidatedInput
|
||||||
import Heroicons.Solid as Heroicons
|
|
||||||
|
|
||||||
type alias Model =
|
type alias Model =
|
||||||
{ filterSelect : FilterSelect.Model
|
{ filterSelect : FilterSelect.Model
|
||||||
, validatedInput : ValidatedInput.Model () (( String, String ))
|
, validatedInput : ValidatedInput.Model () ( String, String )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type Msg
|
type Msg
|
||||||
= FilterSelectSpecific FilterSelect.Msg
|
= FilterSelectSpecific FilterSelect.Msg
|
||||||
| ValidatedInputSpecific ValidatedInput.Msg
|
| ValidatedInputSpecific ValidatedInput.Msg
|
||||||
|
|
||||||
|
|
||||||
init : Model
|
init : Model
|
||||||
init =
|
init =
|
||||||
|
|
||||||
{ filterSelect =
|
{ filterSelect =
|
||||||
[ "Apple"
|
[ "Apple"
|
||||||
, "Kiwi"
|
, "Kiwi"
|
||||||
, "Strawberry"
|
, "Strawberry"
|
||||||
, "Pineapple"
|
, "Pineapple"
|
||||||
, "Mango"
|
, "Mango"
|
||||||
, "Grapes"
|
, "Grapes"
|
||||||
, "Watermelon"
|
, "Watermelon"
|
||||||
, "Orange"
|
, "Orange"
|
||||||
, "Lemon"
|
, "Lemon"
|
||||||
, "Blueberry"
|
, "Blueberry"
|
||||||
, "Grapefruit"
|
, "Grapefruit"
|
||||||
, "Coconut"
|
, "Coconut"
|
||||||
, "Cherry"
|
, "Cherry"
|
||||||
, "Banana"
|
, "Banana"
|
||||||
]
|
]
|
||||||
|> Set.fromList
|
|> Set.fromList
|
||||||
|> FilterSelect.init
|
|> FilterSelect.init
|
||||||
, validatedInput =
|
, validatedInput =
|
||||||
ValidatedInput.init
|
ValidatedInput.init
|
||||||
{ value = ("John","Doe")
|
{ value = ( "John", "Doe" )
|
||||||
, validator =
|
, validator =
|
||||||
\string ->
|
\string ->
|
||||||
case string |> String.split " " of
|
case string |> String.split " " of
|
||||||
[ first, second ] ->
|
[ first, second ] ->
|
||||||
Ok (( first, second ))
|
Ok ( first, second )
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
Err ()
|
Err ()
|
||||||
, toString =
|
, toString =
|
||||||
(\( first, second ) -> first ++ " " ++ second)
|
\( first, second ) -> first ++ " " ++ second
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
update : Msg -> Model -> ( Model, Cmd Msg )
|
update : Msg -> Model -> ( Model, Cmd Msg )
|
||||||
@ -89,6 +90,7 @@ update msg model =
|
|||||||
, Cmd.none
|
, Cmd.none
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
filterSelect : FilterSelect.Model -> Element Msg
|
filterSelect : FilterSelect.Model -> Element Msg
|
||||||
filterSelect model =
|
filterSelect model =
|
||||||
Element.column (Grid.simple ++ Card.large) <|
|
Element.column (Grid.simple ++ Card.large) <|
|
||||||
@ -99,7 +101,7 @@ filterSelect model =
|
|||||||
[ Element.el (Tag.simple ++ Group.left) <| Element.text <| selected
|
[ Element.el (Tag.simple ++ Group.left) <| Element.text <| selected
|
||||||
, Input.button (Tag.simple ++ Group.right ++ Color.danger)
|
, Input.button (Tag.simple ++ Group.right ++ Color.danger)
|
||||||
{ onPress = Just <| FilterSelectSpecific <| FilterSelect.Selected Nothing
|
{ onPress = Just <| FilterSelectSpecific <| FilterSelect.Selected Nothing
|
||||||
, label = Element.html <| Heroicons.x [Attributes.width 16]
|
, label = Element.html <| Heroicons.x [ Attributes.width 16 ]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -108,8 +110,11 @@ filterSelect model =
|
|||||||
[ FilterSelect.viewInput Input.simple
|
[ FilterSelect.viewInput Input.simple
|
||||||
model
|
model
|
||||||
{ msgMapper = FilterSelectSpecific
|
{ msgMapper = FilterSelectSpecific
|
||||||
, placeholder = Just <| Input.placeholder [] <| Element.text <|
|
, placeholder =
|
||||||
"Fruit"
|
Just <|
|
||||||
|
Input.placeholder [] <|
|
||||||
|
Element.text <|
|
||||||
|
"Fruit"
|
||||||
, label = "Fruit"
|
, label = "Fruit"
|
||||||
}
|
}
|
||||||
, model
|
, model
|
||||||
@ -123,11 +128,10 @@ filterSelect model =
|
|||||||
)
|
)
|
||||||
|> Element.wrappedRow [ Element.spacing 10 ]
|
|> Element.wrappedRow [ Element.spacing 10 ]
|
||||||
]
|
]
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
validatedInput : ValidatedInput.Model () ( ( String, String )) -> Element Msg
|
validatedInput : ValidatedInput.Model () ( String, String ) -> Element Msg
|
||||||
validatedInput model =
|
validatedInput model =
|
||||||
Element.column (Grid.simple ++ Card.large) <|
|
Element.column (Grid.simple ++ Card.large) <|
|
||||||
[ Element.el Heading.h3 <| Element.text "Validated Input"
|
[ Element.el Heading.h3 <| Element.text "Validated Input"
|
||||||
@ -136,42 +140,40 @@ validatedInput model =
|
|||||||
{ label = "First Name, Sir Name"
|
{ label = "First Name, Sir Name"
|
||||||
, msgMapper = ValidatedInputSpecific
|
, msgMapper = ValidatedInputSpecific
|
||||||
, placeholder = Nothing
|
, placeholder = Nothing
|
||||||
, readOnly = \maybeTuple ->
|
, readOnly =
|
||||||
Element.row Grid.compact
|
\maybeTuple ->
|
||||||
[ maybeTuple
|
Element.row Grid.compact
|
||||||
|> (\(a,b) -> a ++ " " ++ b)
|
[ maybeTuple
|
||||||
|> Element.text
|
|> (\( a, b ) -> a ++ " " ++ b)
|
||||||
|
|> Element.text
|
||||||
|> Element.el (Tag.simple ++ Group.left)
|
|> Element.el (Tag.simple ++ Group.left)
|
||||||
, Heroicons.pencil [Attributes.width 16]
|
, Heroicons.pencil [ Attributes.width 16 ]
|
||||||
|> Element.html
|
|> Element.html
|
||||||
|>Element.el (Tag.simple ++ Group.right ++ Color.primary)
|
|> Element.el (Tag.simple ++ Group.right ++ Color.primary)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
scrollingNavCard : Element msg
|
scrollingNavCard : Element msg
|
||||||
scrollingNavCard =
|
scrollingNavCard =
|
||||||
[Element.el Heading.h3 <| Element.text "Scrolling Nav"
|
[ Element.el Heading.h3 <| Element.text "Scrolling Nav"
|
||||||
, Element.text "Resize the screen and use the scrollbar to see the scrolling navigation in action."
|
, Element.text "Resize the screen and use the scrollbar to see the scrolling navigation in action."
|
||||||
|> List.singleton
|
|> List.singleton
|
||||||
|> Element.paragraph []
|
|> Element.paragraph []
|
||||||
]
|
]
|
||||||
|> Element.column (Grid.simple ++ Card.large)
|
|> Element.column (Grid.simple ++ Card.large)
|
||||||
|
|
||||||
|
|
||||||
view : Model -> Element Msg
|
view : Model -> Element Msg
|
||||||
view model =
|
view model =
|
||||||
Element.column (Grid.section ++ [Element.centerX])
|
Element.column (Grid.section ++ [ Element.centerX ])
|
||||||
[ Element.el Heading.h2 <| Element.text "Components"
|
[ Element.el Heading.h2 <| Element.text "Components"
|
||||||
, "Components have a Model, an Update- and sometimes even a Subscription-function. It takes some time to set them up correctly."
|
, "Components have a Model, an Update- and sometimes even a Subscription-function. It takes some time to set them up correctly."
|
||||||
|> Element.text
|
|> Element.text
|
||||||
|> List.singleton
|
|> List.singleton
|
||||||
|> Element.paragraph []
|
|> Element.paragraph []
|
||||||
, Element.wrappedRow (Grid.simple ++ [Element.centerX])
|
, Element.wrappedRow (Grid.simple ++ [ Element.centerX ]) <|
|
||||||
<|
|
|
||||||
[ filterSelect model.filterSelect
|
[ filterSelect model.filterSelect
|
||||||
, validatedInput model.validatedInput
|
, validatedInput model.validatedInput
|
||||||
, scrollingNavCard
|
, scrollingNavCard
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
module Example exposing (main)
|
module Example exposing (main)
|
||||||
|
|
||||||
import Browser
|
import Browser
|
||||||
|
import Component
|
||||||
import Element exposing (Element)
|
import Element exposing (Element)
|
||||||
import Element.Input as Input
|
import Element.Input as Input
|
||||||
import Framework
|
import Framework
|
||||||
@ -14,22 +15,23 @@ import Framework.Input as Input
|
|||||||
import Framework.Tag as Tag
|
import Framework.Tag as Tag
|
||||||
import Html exposing (Html)
|
import Html exposing (Html)
|
||||||
import Html.Attributes as Attributes
|
import Html.Attributes as Attributes
|
||||||
|
import Reusable
|
||||||
import Set exposing (Set)
|
import Set exposing (Set)
|
||||||
|
import Stateless
|
||||||
|
import Time
|
||||||
import Widget
|
import Widget
|
||||||
import Widget.FilterSelect as FilterSelect
|
import Widget.FilterSelect as FilterSelect
|
||||||
import Widget.ScrollingNav as ScrollingNav
|
import Widget.ScrollingNav as ScrollingNav
|
||||||
import Widget.ValidatedInput as ValidatedInput
|
|
||||||
import Widget.Snackbar as Snackbar
|
import Widget.Snackbar as Snackbar
|
||||||
import Stateless
|
import Widget.ValidatedInput as ValidatedInput
|
||||||
import Reusable
|
|
||||||
import Component
|
|
||||||
import Time
|
|
||||||
|
|
||||||
type Section
|
type Section
|
||||||
= ComponentViews
|
= ComponentViews
|
||||||
| ReusableViews
|
| ReusableViews
|
||||||
| StatelessViews
|
| StatelessViews
|
||||||
|
|
||||||
|
|
||||||
type alias Model =
|
type alias Model =
|
||||||
{ component : Component.Model
|
{ component : Component.Model
|
||||||
, stateless : Stateless.Model
|
, stateless : Stateless.Model
|
||||||
@ -39,6 +41,7 @@ type alias Model =
|
|||||||
, displayDialog : Bool
|
, displayDialog : Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type Msg
|
type Msg
|
||||||
= StatelessSpecific Stateless.Msg
|
= StatelessSpecific Stateless.Msg
|
||||||
| ReusableSpecific Reusable.Msg
|
| ReusableSpecific Reusable.Msg
|
||||||
@ -59,6 +62,7 @@ init () =
|
|||||||
case section of
|
case section of
|
||||||
ComponentViews ->
|
ComponentViews ->
|
||||||
"Component Views"
|
"Component Views"
|
||||||
|
|
||||||
ReusableViews ->
|
ReusableViews ->
|
||||||
"Reusable Views"
|
"Reusable Views"
|
||||||
|
|
||||||
@ -67,37 +71,35 @@ init () =
|
|||||||
, arrangement = [ StatelessViews, ReusableViews, ComponentViews ]
|
, arrangement = [ StatelessViews, ReusableViews, ComponentViews ]
|
||||||
}
|
}
|
||||||
in
|
in
|
||||||
({ component = Component.init
|
( { component = Component.init
|
||||||
, stateless = Stateless.init
|
, stateless = Stateless.init
|
||||||
, reusable = Reusable.init
|
, reusable = Reusable.init
|
||||||
, scrollingNav = scrollingNav
|
, scrollingNav = scrollingNav
|
||||||
, snackbar = Snackbar.init
|
, snackbar = Snackbar.init
|
||||||
, displayDialog = False
|
, displayDialog = False
|
||||||
}
|
}
|
||||||
|
|
||||||
, cmd |> Cmd.map ScrollingNavSpecific
|
, cmd |> Cmd.map ScrollingNavSpecific
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
view : Model -> Html Msg
|
view : Model -> Html Msg
|
||||||
view model =
|
view model =
|
||||||
[ Element.el [ Element.height <| Element.px <| 42 ] <| Element.none
|
[ Element.el [ Element.height <| Element.px <| 42 ] <| Element.none
|
||||||
, [ Element.el Heading.h1 <| Element.text "Elm-Ui-Widgets"
|
, [ Element.el Heading.h1 <| Element.text "Elm-Ui-Widgets"
|
||||||
, model.scrollingNav
|
, model.scrollingNav
|
||||||
|> ScrollingNav.view
|
|> ScrollingNav.view
|
||||||
(\section ->
|
(\section ->
|
||||||
case section of
|
case section of
|
||||||
ComponentViews ->
|
ComponentViews ->
|
||||||
model.component
|
model.component
|
||||||
|> Component.view
|
|> Component.view
|
||||||
|> Element.map ComponentSpecific
|
|> Element.map ComponentSpecific
|
||||||
|
|
||||||
ReusableViews ->
|
ReusableViews ->
|
||||||
Reusable.view
|
Reusable.view
|
||||||
{addSnackbar = AddSnackbar
|
{ addSnackbar = AddSnackbar
|
||||||
,model = model.reusable
|
, model = model.reusable
|
||||||
,msgMapper = ReusableSpecific
|
, msgMapper = ReusableSpecific
|
||||||
}
|
}
|
||||||
|
|
||||||
StatelessViews ->
|
StatelessViews ->
|
||||||
@ -107,7 +109,7 @@ view model =
|
|||||||
}
|
}
|
||||||
model.stateless
|
model.stateless
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|> Element.column Framework.container
|
|> Element.column Framework.container
|
||||||
]
|
]
|
||||||
|> Element.column Grid.compact
|
|> Element.column Grid.compact
|
||||||
@ -120,6 +122,7 @@ view model =
|
|||||||
case string of
|
case string of
|
||||||
"Component Views" ->
|
"Component Views" ->
|
||||||
Just ComponentViews
|
Just ComponentViews
|
||||||
|
|
||||||
"Reusable Views" ->
|
"Reusable Views" ->
|
||||||
Just ReusableViews
|
Just ReusableViews
|
||||||
|
|
||||||
@ -130,14 +133,16 @@ view model =
|
|||||||
Nothing
|
Nothing
|
||||||
, label = Element.text
|
, label = Element.text
|
||||||
, msgMapper = ScrollingNavSpecific
|
, msgMapper = ScrollingNavSpecific
|
||||||
, attributes = \selected -> Button.simple
|
, attributes =
|
||||||
++ Group.center
|
\selected ->
|
||||||
++ (if selected then
|
Button.simple
|
||||||
Color.primary
|
++ Group.center
|
||||||
|
++ (if selected then
|
||||||
|
Color.primary
|
||||||
|
|
||||||
else
|
else
|
||||||
Color.dark
|
Color.dark
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|> Widget.select
|
|> Widget.select
|
||||||
|> Element.row
|
|> Element.row
|
||||||
@ -157,38 +162,41 @@ view model =
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
, Element.inFront <|
|
, Element.inFront <|
|
||||||
( model.snackbar
|
(model.snackbar
|
||||||
|> Snackbar.current
|
|> Snackbar.current
|
||||||
|> Maybe.map
|
|> Maybe.map
|
||||||
(Element.text >>
|
(Element.text
|
||||||
List.singleton >>
|
>> List.singleton
|
||||||
Element.paragraph (Card.simple ++ Color.dark)
|
>> Element.paragraph (Card.simple ++ Color.dark)
|
||||||
>> Element.el [Element.padding 8,Element.alignBottom
|
>> Element.el
|
||||||
, Element.alignRight]
|
[ Element.padding 8
|
||||||
|
, Element.alignBottom
|
||||||
|
, Element.alignRight
|
||||||
|
]
|
||||||
)
|
)
|
||||||
|> Maybe.withDefault Element.none
|
|> Maybe.withDefault Element.none
|
||||||
)
|
)
|
||||||
, Element.inFront <|
|
, Element.inFront <|
|
||||||
if model.displayDialog then
|
if model.displayDialog then
|
||||||
Widget.dialog {
|
Widget.dialog
|
||||||
onDismiss = Just <| ToggleDialog False
|
{ onDismiss = Just <| ToggleDialog False
|
||||||
,content =
|
, content =
|
||||||
[ Element.el Heading.h3 <| Element.text "Dialog"
|
[ Element.el Heading.h3 <| Element.text "Dialog"
|
||||||
, "This is a dialog window"
|
, "This is a dialog window"
|
||||||
|> Element.text
|
|> Element.text
|
||||||
|> List.singleton
|
|> List.singleton
|
||||||
|> Element.paragraph []
|
|> Element.paragraph []
|
||||||
, Input.button (Button.simple ++ [Element.alignRight])
|
, Input.button (Button.simple ++ [ Element.alignRight ])
|
||||||
{onPress = Just <| ToggleDialog False
|
{ onPress = Just <| ToggleDialog False
|
||||||
, label = Element.text "Ok"
|
, label = Element.text "Ok"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|>Element.column (Grid.simple ++ Card.large)
|
|> Element.column (Grid.simple ++ Card.large)
|
||||||
} else Element.none
|
}
|
||||||
]
|
|
||||||
|
|
||||||
|
else
|
||||||
|
Element.none
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
update : Msg -> Model -> ( Model, Cmd Msg )
|
update : Msg -> Model -> ( Model, Cmd Msg )
|
||||||
@ -206,13 +214,15 @@ update msg model =
|
|||||||
(Cmd.map ComponentSpecific)
|
(Cmd.map ComponentSpecific)
|
||||||
|
|
||||||
ReusableSpecific m ->
|
ReusableSpecific m ->
|
||||||
(model.reusable
|
( model.reusable
|
||||||
|> Reusable.update m
|
|> Reusable.update m
|
||||||
|> (\reusable ->
|
|> (\reusable ->
|
||||||
{ model
|
{ model
|
||||||
| reusable = reusable
|
| reusable = reusable
|
||||||
}
|
}
|
||||||
),Cmd.none)
|
)
|
||||||
|
, Cmd.none
|
||||||
|
)
|
||||||
|
|
||||||
StatelessSpecific m ->
|
StatelessSpecific m ->
|
||||||
model.stateless
|
model.stateless
|
||||||
@ -225,7 +235,6 @@ update msg model =
|
|||||||
)
|
)
|
||||||
(Cmd.map StatelessSpecific)
|
(Cmd.map StatelessSpecific)
|
||||||
|
|
||||||
|
|
||||||
ScrollingNavSpecific m ->
|
ScrollingNavSpecific m ->
|
||||||
model.scrollingNav
|
model.scrollingNav
|
||||||
|> ScrollingNav.update m
|
|> ScrollingNav.update m
|
||||||
@ -238,12 +247,14 @@ update msg model =
|
|||||||
(Cmd.map ScrollingNavSpecific)
|
(Cmd.map ScrollingNavSpecific)
|
||||||
|
|
||||||
TimePassed int ->
|
TimePassed int ->
|
||||||
({ model
|
( { model
|
||||||
| snackbar = model.snackbar |> Snackbar.timePassed int
|
| snackbar = model.snackbar |> Snackbar.timePassed int
|
||||||
},Cmd.none)
|
}
|
||||||
|
, Cmd.none
|
||||||
|
)
|
||||||
|
|
||||||
AddSnackbar string ->
|
AddSnackbar string ->
|
||||||
( { model | snackbar = model.snackbar |> Snackbar.insert string}
|
( { model | snackbar = model.snackbar |> Snackbar.insert string }
|
||||||
, Cmd.none
|
, Cmd.none
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -252,13 +263,14 @@ update msg model =
|
|||||||
, Cmd.none
|
, Cmd.none
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
subscriptions : Model -> Sub Msg
|
subscriptions : Model -> Sub Msg
|
||||||
subscriptions model=
|
subscriptions model =
|
||||||
Sub.batch
|
Sub.batch
|
||||||
[ScrollingNav.subscriptions
|
[ ScrollingNav.subscriptions
|
||||||
|> Sub.map ScrollingNavSpecific
|
|> Sub.map ScrollingNavSpecific
|
||||||
, Time.every 50 (always ( TimePassed 50))
|
, Time.every 50 (always (TimePassed 50))
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
main : Program () Model Msg
|
main : Program () Model Msg
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
module Reusable exposing (Model,Msg,init,view,update)
|
module Reusable exposing (Model, Msg, init, update, view)
|
||||||
|
|
||||||
import Browser
|
import Browser
|
||||||
import Element exposing (Element,Color)
|
import Element exposing (Color, Element)
|
||||||
import Element.Input as Input
|
|
||||||
import Element.Background as Background
|
import Element.Background as Background
|
||||||
|
import Element.Font as Font
|
||||||
|
import Element.Input as Input
|
||||||
import Framework
|
import Framework
|
||||||
import Framework.Button as Button
|
import Framework.Button as Button
|
||||||
import Framework.Card as Card
|
import Framework.Card as Card
|
||||||
@ -13,63 +14,70 @@ import Framework.Group as Group
|
|||||||
import Framework.Heading as Heading
|
import Framework.Heading as Heading
|
||||||
import Framework.Input as Input
|
import Framework.Input as Input
|
||||||
import Framework.Tag as Tag
|
import Framework.Tag as Tag
|
||||||
|
import Heroicons.Solid as Heroicons
|
||||||
import Html exposing (Html)
|
import Html exposing (Html)
|
||||||
import Html.Attributes as Attributes
|
import Html.Attributes as Attributes
|
||||||
import Set exposing (Set)
|
import Set exposing (Set)
|
||||||
|
import Time
|
||||||
import Widget
|
import Widget
|
||||||
import Widget.FilterSelect as FilterSelect
|
import Widget.FilterSelect as FilterSelect
|
||||||
import Widget.ScrollingNav as ScrollingNav
|
import Widget.ScrollingNav as ScrollingNav
|
||||||
import Widget.ValidatedInput as ValidatedInput
|
|
||||||
import Widget.Snackbar as Snackbar
|
import Widget.Snackbar as Snackbar
|
||||||
import Widget.SortTable as SortTable
|
import Widget.SortTable as SortTable
|
||||||
import Time
|
import Widget.ValidatedInput as ValidatedInput
|
||||||
import Heroicons.Solid as Heroicons
|
|
||||||
import Element.Font as Font
|
|
||||||
|
|
||||||
type alias Model =
|
type alias Model =
|
||||||
SortTable.Model
|
SortTable.Model
|
||||||
|
|
||||||
type Msg =
|
|
||||||
SortBy {title : String, asc : Bool }
|
type Msg
|
||||||
|
= SortBy { title : String, asc : Bool }
|
||||||
|
|
||||||
|
|
||||||
type alias Item =
|
type alias Item =
|
||||||
{name : String
|
{ name : String
|
||||||
,amount : Int
|
, amount : Int
|
||||||
,price : Float
|
, price : Float
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
update : Msg -> Model -> Model
|
update : Msg -> Model -> Model
|
||||||
update msg model =
|
update msg model =
|
||||||
case msg of
|
case msg of
|
||||||
SortBy m ->
|
SortBy m ->
|
||||||
m
|
m
|
||||||
|
|
||||||
|
|
||||||
init : Model
|
init : Model
|
||||||
init =
|
init =
|
||||||
SortTable.sortBy {title="Name",asc=True}
|
SortTable.sortBy { title = "Name", asc = True }
|
||||||
|
|
||||||
|
|
||||||
snackbar : (String -> msg) -> Element msg
|
snackbar : (String -> msg) -> Element msg
|
||||||
snackbar addSnackbar =
|
snackbar addSnackbar =
|
||||||
[ Element.el Heading.h3 <| Element.text "Snackbar"
|
[ Element.el Heading.h3 <| Element.text "Snackbar"
|
||||||
, Input.button Button.simple
|
, Input.button Button.simple
|
||||||
{ onPress = Just <| addSnackbar "This is a notification. It will disappear after 10 seconds."
|
{ onPress = Just <| addSnackbar "This is a notification. It will disappear after 10 seconds."
|
||||||
, label = "Add Notification"
|
, label =
|
||||||
|> Element.text
|
"Add Notification"
|
||||||
|> List.singleton
|
|> Element.text
|
||||||
|> Element.paragraph []
|
|> List.singleton
|
||||||
|
|> Element.paragraph []
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|> Element.column (Grid.simple ++ Card.large)
|
|> Element.column (Grid.simple ++ Card.large)
|
||||||
|
|
||||||
|
|
||||||
sortTable : SortTable.Model -> Element Msg
|
sortTable : SortTable.Model -> Element Msg
|
||||||
sortTable model =
|
sortTable model =
|
||||||
[ Element.el Heading.h3 <| Element.text "Sort Table"
|
[ Element.el Heading.h3 <| Element.text "Sort Table"
|
||||||
, SortTable.view
|
, SortTable.view
|
||||||
{ content =
|
{ content =
|
||||||
[ {id = 1, name = "Antonio", rating = 2.456}
|
[ { id = 1, name = "Antonio", rating = 2.456 }
|
||||||
, {id = 2, name = "Ana", rating = 1.34}
|
, { id = 2, name = "Ana", rating = 1.34 }
|
||||||
, {id = 3, name = "Alfred", rating = 4.22}
|
, { id = 3, name = "Alfred", rating = 4.22 }
|
||||||
, {id = 4, name = "Thomas", rating = 3 }
|
, { id = 4, name = "Thomas", rating = 3 }
|
||||||
]
|
]
|
||||||
, columns =
|
, columns =
|
||||||
[ SortTable.intColumn
|
[ SortTable.intColumn
|
||||||
@ -90,54 +98,65 @@ sortTable model =
|
|||||||
]
|
]
|
||||||
, model = model
|
, model = model
|
||||||
}
|
}
|
||||||
|> (\{data,columns} ->
|
|> (\{ data, columns } ->
|
||||||
{data = data
|
{ data = data
|
||||||
,columns = columns
|
, columns =
|
||||||
|> List.map (\config->
|
columns
|
||||||
{ header =
|
|> List.map
|
||||||
Input.button [Font.bold]
|
(\config ->
|
||||||
{ onPress = {title = config.header
|
{ header =
|
||||||
,asc = if config.header == model.title then
|
Input.button [ Font.bold ]
|
||||||
not model.asc
|
{ onPress =
|
||||||
else
|
{ title = config.header
|
||||||
True
|
, asc =
|
||||||
}|> SortBy |> Just
|
if config.header == model.title then
|
||||||
|
not model.asc
|
||||||
|
|
||||||
|
else
|
||||||
|
True
|
||||||
|
}
|
||||||
|
|> SortBy
|
||||||
|
|> Just
|
||||||
, label =
|
, label =
|
||||||
if config.header == model.title then
|
if config.header == model.title then
|
||||||
[config.header |> Element.text
|
[ config.header |> Element.text
|
||||||
, Element.html <|if model.asc then
|
, Element.html <|
|
||||||
Heroicons.cheveronUp [Attributes.width 16]
|
if model.asc then
|
||||||
|
Heroicons.cheveronUp [ Attributes.width 16 ]
|
||||||
|
|
||||||
else
|
else
|
||||||
Heroicons.cheveronDown [Attributes.width 16]
|
Heroicons.cheveronDown [ Attributes.width 16 ]
|
||||||
]
|
]
|
||||||
|> Element.row (Grid.simple ++ [Font.bold])
|
|> Element.row (Grid.simple ++ [ Font.bold ])
|
||||||
else
|
|
||||||
|
|
||||||
config.header |> Element.text
|
else
|
||||||
|
config.header |> Element.text
|
||||||
|
}
|
||||||
|
, view = config.view >> Element.text
|
||||||
|
, width = Element.fill
|
||||||
}
|
}
|
||||||
|
)
|
||||||
, view = config.view >> Element.text
|
}
|
||||||
, width = Element.fill
|
)
|
||||||
}
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|> Element.table Grid.simple
|
|> Element.table Grid.simple
|
||||||
]
|
]
|
||||||
|> Element.column (Grid.simple ++ Card.large)
|
|> Element.column (Grid.simple ++ Card.large)
|
||||||
|
|
||||||
view : { addSnackbar : String -> msg
|
|
||||||
|
view :
|
||||||
|
{ addSnackbar : String -> msg
|
||||||
, msgMapper : Msg -> msg
|
, msgMapper : Msg -> msg
|
||||||
, model : Model } -> Element msg
|
, model : Model
|
||||||
view {addSnackbar,msgMapper,model} =
|
}
|
||||||
Element.column (Grid.section ++ [Element.centerX])
|
-> Element msg
|
||||||
|
view { addSnackbar, msgMapper, model } =
|
||||||
|
Element.column (Grid.section ++ [ Element.centerX ])
|
||||||
[ Element.el Heading.h2 <| Element.text "Reusable Views"
|
[ Element.el Heading.h2 <| Element.text "Reusable Views"
|
||||||
, "Reusable views have an internal state but no update function. You will need to do some wiring, but nothing complicated."
|
, "Reusable views have an internal state but no update function. You will need to do some wiring, but nothing complicated."
|
||||||
|> Element.text
|
|> Element.text
|
||||||
|> List.singleton
|
|> List.singleton
|
||||||
|> Element.paragraph []
|
|> Element.paragraph []
|
||||||
, Element.wrappedRow (Grid.simple ++ [Element.centerX])
|
, Element.wrappedRow (Grid.simple ++ [ Element.centerX ]) <|
|
||||||
<|
|
|
||||||
[ snackbar addSnackbar
|
[ snackbar addSnackbar
|
||||||
, sortTable model |> Element.map msgMapper
|
, sortTable model |> Element.map msgMapper
|
||||||
]
|
]
|
||||||
|
@ -1,23 +1,24 @@
|
|||||||
module Stateless exposing (Model,Msg,init,update,view)
|
module Stateless exposing (Model, Msg, init, update, view)
|
||||||
|
|
||||||
|
import Array exposing (Array)
|
||||||
import Element exposing (Element)
|
import Element exposing (Element)
|
||||||
import Element.Input as Input
|
|
||||||
import Element.Background as Background
|
import Element.Background as Background
|
||||||
import Element.Border as Border
|
import Element.Border as Border
|
||||||
import Set exposing (Set)
|
import Element.Input as Input
|
||||||
import Framework.Grid as Grid
|
|
||||||
import Framework.Button as Button
|
import Framework.Button as Button
|
||||||
import Framework.Card as Card
|
import Framework.Card as Card
|
||||||
import Framework.Color as Color
|
import Framework.Color as Color
|
||||||
|
import Framework.Grid as Grid
|
||||||
import Framework.Group as Group
|
import Framework.Group as Group
|
||||||
import Framework.Heading as Heading
|
import Framework.Heading as Heading
|
||||||
import Framework.Input as Input
|
import Framework.Input as Input
|
||||||
import Framework.Tag as Tag
|
import Framework.Tag as Tag
|
||||||
import Heroicons.Solid as Heroicons
|
import Heroicons.Solid as Heroicons
|
||||||
import Widget
|
|
||||||
import Html exposing (Html)
|
import Html exposing (Html)
|
||||||
import Html.Attributes as Attributes
|
import Html.Attributes as Attributes
|
||||||
import Array exposing (Array)
|
import Set exposing (Set)
|
||||||
|
import Widget
|
||||||
|
|
||||||
|
|
||||||
type alias Model =
|
type alias Model =
|
||||||
{ selected : Maybe Int
|
{ selected : Maybe Int
|
||||||
@ -27,13 +28,15 @@ type alias Model =
|
|||||||
, tab : Int
|
, tab : Int
|
||||||
}
|
}
|
||||||
|
|
||||||
type Msg =
|
|
||||||
ChangedSelected Int
|
type Msg
|
||||||
|
= ChangedSelected Int
|
||||||
| ChangedMultiSelected Int
|
| ChangedMultiSelected Int
|
||||||
| ToggleCollapsable Bool
|
| ToggleCollapsable Bool
|
||||||
| ChangedTab Int
|
| ChangedTab Int
|
||||||
| SetCarousel Int
|
| SetCarousel Int
|
||||||
|
|
||||||
|
|
||||||
init : Model
|
init : Model
|
||||||
init =
|
init =
|
||||||
{ selected = Nothing
|
{ selected = Nothing
|
||||||
@ -43,7 +46,8 @@ init =
|
|||||||
, tab = 1
|
, tab = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
update : Msg -> Model -> (Model,Cmd Msg)
|
|
||||||
|
update : Msg -> Model -> ( Model, Cmd Msg )
|
||||||
update msg model =
|
update msg model =
|
||||||
case msg of
|
case msg of
|
||||||
ChangedSelected int ->
|
ChangedSelected int ->
|
||||||
@ -56,32 +60,38 @@ update msg model =
|
|||||||
ChangedMultiSelected int ->
|
ChangedMultiSelected int ->
|
||||||
( { model
|
( { model
|
||||||
| multiSelected =
|
| multiSelected =
|
||||||
model.multiSelected |>
|
model.multiSelected
|
||||||
if model.multiSelected |> Set.member int then
|
|> (if model.multiSelected |> Set.member int then
|
||||||
Set.remove int
|
Set.remove int
|
||||||
else
|
|
||||||
Set.insert int
|
else
|
||||||
}
|
Set.insert int
|
||||||
, Cmd.none )
|
)
|
||||||
|
}
|
||||||
|
, Cmd.none
|
||||||
|
)
|
||||||
|
|
||||||
ToggleCollapsable bool ->
|
ToggleCollapsable bool ->
|
||||||
( { model
|
( { model
|
||||||
| isCollapsed = bool
|
| isCollapsed = bool
|
||||||
}
|
}
|
||||||
, Cmd.none)
|
, Cmd.none
|
||||||
|
)
|
||||||
|
|
||||||
SetCarousel int ->
|
SetCarousel int ->
|
||||||
( if (int < 0) || (int > 3) then
|
( if (int < 0) || (int > 3) then
|
||||||
model
|
model
|
||||||
|
|
||||||
else
|
else
|
||||||
{model
|
{ model
|
||||||
| carousel = int
|
| carousel = int
|
||||||
}
|
}
|
||||||
, Cmd.none
|
, Cmd.none
|
||||||
)
|
)
|
||||||
|
|
||||||
ChangedTab int ->
|
ChangedTab int ->
|
||||||
( {model | tab = int }, Cmd.none )
|
( { model | tab = int }, Cmd.none )
|
||||||
|
|
||||||
|
|
||||||
select : Model -> Element Msg
|
select : Model -> Element Msg
|
||||||
select model =
|
select model =
|
||||||
@ -91,20 +101,40 @@ select model =
|
|||||||
, options = [ 1, 2, 42 ]
|
, options = [ 1, 2, 42 ]
|
||||||
, label = String.fromInt >> Element.text
|
, label = String.fromInt >> Element.text
|
||||||
, onChange = ChangedSelected
|
, onChange = ChangedSelected
|
||||||
, attributes = \selected ->
|
, attributes =
|
||||||
Button.simple
|
\selected ->
|
||||||
++ Group.center
|
Button.simple
|
||||||
++ (if selected then
|
++ [ Border.width 0
|
||||||
Color.primary
|
, Border.rounded 0
|
||||||
|
]
|
||||||
|
++ (if selected then
|
||||||
|
Color.primary
|
||||||
|
|
||||||
else
|
else
|
||||||
[]
|
[]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|> Element.row (Grid.compact)
|
|> List.indexedMap
|
||||||
|
(\i ->
|
||||||
|
Element.el
|
||||||
|
(Button.simple
|
||||||
|
++ [ Element.padding <| 0 ]
|
||||||
|
++ (if i == 0 then
|
||||||
|
Group.left
|
||||||
|
|
||||||
|
else if i == 2 then
|
||||||
|
Group.right
|
||||||
|
|
||||||
|
else
|
||||||
|
Group.center
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|> Element.row Grid.compact
|
||||||
]
|
]
|
||||||
|> Element.column (Grid.simple ++ Card.large)
|
|> Element.column (Grid.simple ++ Card.large)
|
||||||
|
|
||||||
|
|
||||||
multiSelect : Model -> Element Msg
|
multiSelect : Model -> Element Msg
|
||||||
multiSelect model =
|
multiSelect model =
|
||||||
[ Element.el Heading.h3 <| Element.text "Multi Select"
|
[ Element.el Heading.h3 <| Element.text "Multi Select"
|
||||||
@ -113,16 +143,35 @@ multiSelect model =
|
|||||||
, options = [ 1, 2, 42 ]
|
, options = [ 1, 2, 42 ]
|
||||||
, label = String.fromInt >> Element.text
|
, label = String.fromInt >> Element.text
|
||||||
, onChange = ChangedMultiSelected
|
, onChange = ChangedMultiSelected
|
||||||
, attributes = \selected ->
|
, attributes =
|
||||||
(Button.simple
|
\selected ->
|
||||||
++ Group.center
|
Button.simple
|
||||||
++ if selected then
|
++ [ Border.width 0
|
||||||
Color.primary
|
, Border.rounded 0
|
||||||
|
]
|
||||||
|
++ (if selected then
|
||||||
|
Color.primary
|
||||||
|
|
||||||
else
|
else
|
||||||
[]
|
[]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|> List.indexedMap
|
||||||
|
(\i ->
|
||||||
|
Element.el
|
||||||
|
(Button.simple
|
||||||
|
++ [ Element.padding <| 0 ]
|
||||||
|
++ (if i == 0 then
|
||||||
|
Group.left
|
||||||
|
|
||||||
|
else if i == 2 then
|
||||||
|
Group.right
|
||||||
|
|
||||||
|
else
|
||||||
|
Group.center
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|> Element.row Grid.compact
|
|> Element.row Grid.compact
|
||||||
]
|
]
|
||||||
|> Element.column (Grid.simple ++ Card.large)
|
|> Element.column (Grid.simple ++ Card.large)
|
||||||
@ -130,55 +179,64 @@ multiSelect model =
|
|||||||
|
|
||||||
collapsable : Model -> Element Msg
|
collapsable : Model -> Element Msg
|
||||||
collapsable model =
|
collapsable model =
|
||||||
[Element.el Heading.h3 <| Element.text "Collapsable"
|
[ Element.el Heading.h3 <| Element.text "Collapsable"
|
||||||
,Widget.collapsable
|
, Widget.collapsable
|
||||||
{onToggle = ToggleCollapsable
|
{ onToggle = ToggleCollapsable
|
||||||
,isCollapsed = model.isCollapsed
|
, isCollapsed = model.isCollapsed
|
||||||
,label = Element.row Grid.compact
|
, label =
|
||||||
[ Element.html <|
|
Element.row Grid.compact
|
||||||
if model.isCollapsed then
|
[ Element.html <|
|
||||||
Heroicons.cheveronRight [ Attributes.width 20]
|
if model.isCollapsed then
|
||||||
else
|
Heroicons.cheveronRight [ Attributes.width 20 ]
|
||||||
Heroicons.cheveronDown [ Attributes.width 20]
|
|
||||||
, Element.el Heading.h4 <|Element.text <| "Title"
|
else
|
||||||
]
|
Heroicons.cheveronDown [ Attributes.width 20 ]
|
||||||
,content = Element.text <| "Hello World"
|
, Element.el Heading.h4 <| Element.text <| "Title"
|
||||||
|
]
|
||||||
|
, content = Element.text <| "Hello World"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|> Element.column (Grid.simple ++ Card.large)
|
|> Element.column (Grid.simple ++ Card.large)
|
||||||
|
|
||||||
|
|
||||||
tab : Model -> Element Msg
|
tab : Model -> Element Msg
|
||||||
tab model =
|
tab model =
|
||||||
[Element.el Heading.h3 <| Element.text "Tab"
|
[ Element.el Heading.h3 <| Element.text "Tab"
|
||||||
,Widget.tab Grid.simple
|
, Widget.tab Grid.simple
|
||||||
{ selected = model.tab
|
{ selected = model.tab
|
||||||
, options = [1,2,3]
|
, options = [ 1, 2, 3 ]
|
||||||
, onChange = ChangedTab
|
, onChange = ChangedTab
|
||||||
, label = \int -> "Tab " ++ String.fromInt int |> Element.text
|
, label = \int -> "Tab " ++ String.fromInt int |> Element.text
|
||||||
, content = \selected ->
|
, content =
|
||||||
(case selected of
|
\selected ->
|
||||||
1 ->
|
(case selected of
|
||||||
"This is Tab 1"
|
1 ->
|
||||||
2 ->
|
"This is Tab 1"
|
||||||
"This is the second tab"
|
|
||||||
3 ->
|
2 ->
|
||||||
"The thrid and last tab"
|
"This is the second tab"
|
||||||
_ ->
|
|
||||||
"Please select a tab"
|
3 ->
|
||||||
|
"The thrid and last tab"
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
"Please select a tab"
|
||||||
)
|
)
|
||||||
|>Element.text
|
|> Element.text
|
||||||
|> Element.el (Card.small ++ Group.bottom)
|
|> Element.el (Card.small ++ Group.bottom)
|
||||||
, attributes = \selected ->
|
, attributes =
|
||||||
(Button.simple
|
\selected ->
|
||||||
++ Group.top
|
Button.simple
|
||||||
++ if selected then
|
++ Group.top
|
||||||
Color.primary
|
++ (if selected then
|
||||||
else
|
Color.primary
|
||||||
[]
|
|
||||||
)
|
else
|
||||||
|
[]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|> Element.column (Grid.simple ++ Card.large)
|
|> Element.column (Grid.simple ++ Card.large)
|
||||||
|
|
||||||
|
|
||||||
dialog : msg -> Model -> Element msg
|
dialog : msg -> Model -> Element msg
|
||||||
@ -189,42 +247,48 @@ dialog showDialog model =
|
|||||||
, label = Element.text <| "Show Dialog"
|
, label = Element.text <| "Show Dialog"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|> Element.column (Grid.simple ++ Card.large)
|
|> Element.column (Grid.simple ++ Card.large)
|
||||||
|
|
||||||
|
|
||||||
carousel : Model -> Element Msg
|
carousel : Model -> Element Msg
|
||||||
carousel model =
|
carousel model =
|
||||||
[ Element.el Heading.h3 <| Element.text "Carousel"
|
[ Element.el Heading.h3 <| Element.text "Carousel"
|
||||||
, Widget.carousel
|
, Widget.carousel
|
||||||
{content = (Color.cyan,[Color.yellow, Color.green , Color.red ]|> Array.fromList)
|
{ content = ( Color.cyan, [ Color.yellow, Color.green, Color.red ] |> Array.fromList )
|
||||||
,current = model.carousel
|
, current = model.carousel
|
||||||
, label = \c ->
|
, label =
|
||||||
[ Input.button [Element.centerY]
|
\c ->
|
||||||
|
[ Input.button [ Element.centerY ]
|
||||||
{ onPress = Just <| SetCarousel <| model.carousel - 1
|
{ onPress = Just <| SetCarousel <| model.carousel - 1
|
||||||
, label = Heroicons.cheveronLeft [Attributes.width 20]
|
, label =
|
||||||
|> Element.html
|
Heroicons.cheveronLeft [ Attributes.width 20 ]
|
||||||
|
|> Element.html
|
||||||
}
|
}
|
||||||
, Element.el
|
, Element.el
|
||||||
(Card.simple
|
(Card.simple
|
||||||
++ [ Background.color <| c
|
++ [ Background.color <| c
|
||||||
, Element.height <| Element.px <| 100
|
, Element.height <| Element.px <| 100
|
||||||
, Element.width <| Element.px <| 100
|
, Element.width <| Element.px <| 100
|
||||||
]
|
]
|
||||||
) <| Element.none
|
)
|
||||||
, Input.button [Element.centerY]
|
<|
|
||||||
|
Element.none
|
||||||
|
, Input.button [ Element.centerY ]
|
||||||
{ onPress = Just <| SetCarousel <| model.carousel + 1
|
{ onPress = Just <| SetCarousel <| model.carousel + 1
|
||||||
, label = Heroicons.cheveronRight [Attributes.width 20]
|
, label =
|
||||||
|> Element.html
|
Heroicons.cheveronRight [ Attributes.width 20 ]
|
||||||
|
|> Element.html
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|> Element.row (Grid.simple ++ [Element.centerX, Element.width<| Element.shrink])
|
|> Element.row (Grid.simple ++ [ Element.centerX, Element.width <| Element.shrink ])
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|> Element.column (Grid.simple ++ Card.large)
|
|> Element.column (Grid.simple ++ Card.large)
|
||||||
|
|
||||||
|
|
||||||
view : { msgMapper : Msg -> msg, showDialog : msg} -> Model -> Element msg
|
view : { msgMapper : Msg -> msg, showDialog : msg } -> Model -> Element msg
|
||||||
view {msgMapper,showDialog} model =
|
view { msgMapper, showDialog } model =
|
||||||
Element.column (Grid.section)
|
Element.column Grid.section
|
||||||
[ Element.el Heading.h2 <| Element.text "Stateless Views"
|
[ Element.el Heading.h2 <| Element.text "Stateless Views"
|
||||||
, "Stateless views are simple functions that view some content. No wiring required."
|
, "Stateless views are simple functions that view some content. No wiring required."
|
||||||
|> Element.text
|
|> Element.text
|
||||||
@ -232,7 +296,7 @@ view {msgMapper,showDialog} model =
|
|||||||
|> Element.paragraph []
|
|> Element.paragraph []
|
||||||
, Element.wrappedRow
|
, Element.wrappedRow
|
||||||
Grid.simple
|
Grid.simple
|
||||||
<|
|
<|
|
||||||
[ select model |> Element.map msgMapper
|
[ select model |> Element.map msgMapper
|
||||||
, multiSelect model |> Element.map msgMapper
|
, multiSelect model |> Element.map msgMapper
|
||||||
, collapsable model |> Element.map msgMapper
|
, collapsable model |> Element.map msgMapper
|
||||||
|
@ -11,7 +11,7 @@ import Element.Input as Input exposing (Placeholder)
|
|||||||
import Set exposing (Set)
|
import Set exposing (Set)
|
||||||
|
|
||||||
|
|
||||||
{-| The Model
|
{-| The Model containing the raw value, the selected value and all the possible options.
|
||||||
-}
|
-}
|
||||||
type alias Model =
|
type alias Model =
|
||||||
{ raw : String
|
{ raw : String
|
||||||
|
@ -28,29 +28,30 @@ import Time
|
|||||||
|
|
||||||
|
|
||||||
{-| -}
|
{-| -}
|
||||||
type alias Model elem =
|
type alias Model section =
|
||||||
{ labels : elem -> String
|
{ labels : section -> String
|
||||||
, positions : IntDict String
|
, positions : IntDict String
|
||||||
, arrangement : List elem
|
, arrangement : List section
|
||||||
, scrollPos : Int
|
, scrollPos : Int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
{-| -}
|
{-| -}
|
||||||
type Msg elem
|
type Msg section
|
||||||
= GotHeaderPos elem (Result Dom.Error Int)
|
= GotHeaderPos section (Result Dom.Error Int)
|
||||||
| ChangedViewport (Result Dom.Error ())
|
| ChangedViewport (Result Dom.Error ())
|
||||||
| SyncPosition Int
|
| SyncPosition Int
|
||||||
| JumpTo elem
|
| JumpTo section
|
||||||
| TimePassed
|
| TimePassed
|
||||||
|
|
||||||
|
|
||||||
{-| -}
|
{-| The intial state include the labels and the arrangement of the sections
|
||||||
|
-}
|
||||||
init :
|
init :
|
||||||
{ labels : elem -> String
|
{ labels : section -> String
|
||||||
, arrangement : List elem
|
, arrangement : List section
|
||||||
}
|
}
|
||||||
-> ( Model elem, Cmd (Msg elem) )
|
-> ( Model section, Cmd (Msg section) )
|
||||||
init { labels, arrangement } =
|
init { labels, arrangement } =
|
||||||
{ labels = labels
|
{ labels = labels
|
||||||
, positions = IntDict.empty
|
, positions = IntDict.empty
|
||||||
@ -65,7 +66,7 @@ init { labels, arrangement } =
|
|||||||
|
|
||||||
|
|
||||||
{-| -}
|
{-| -}
|
||||||
update : Msg elem -> Model elem -> ( Model elem, Cmd (Msg elem) )
|
update : Msg section -> Model section -> ( Model section, Cmd (Msg section) )
|
||||||
update msg model =
|
update msg model =
|
||||||
case msg of
|
case msg of
|
||||||
GotHeaderPos label result ->
|
GotHeaderPos label result ->
|
||||||
@ -113,8 +114,9 @@ subscriptions =
|
|||||||
Time.every 1000 (always TimePassed)
|
Time.every 1000 (always TimePassed)
|
||||||
|
|
||||||
|
|
||||||
{-| -}
|
{-| scrolls the screen to the respective section
|
||||||
jumpTo : elem -> Model elem -> Cmd (Msg msg)
|
-}
|
||||||
|
jumpTo : section -> Model section -> Cmd (Msg msg)
|
||||||
jumpTo section { labels } =
|
jumpTo section { labels } =
|
||||||
Dom.getElement (section |> labels)
|
Dom.getElement (section |> labels)
|
||||||
|> Task.andThen
|
|> Task.andThen
|
||||||
@ -125,7 +127,7 @@ jumpTo section { labels } =
|
|||||||
|
|
||||||
|
|
||||||
{-| -}
|
{-| -}
|
||||||
syncPositions : Model elem -> Cmd (Msg elem)
|
syncPositions : Model section -> Cmd (Msg section)
|
||||||
syncPositions { labels, arrangement } =
|
syncPositions { labels, arrangement } =
|
||||||
arrangement
|
arrangement
|
||||||
|> List.map
|
|> List.map
|
||||||
@ -145,16 +147,16 @@ syncPositions { labels, arrangement } =
|
|||||||
{-| -}
|
{-| -}
|
||||||
viewSections :
|
viewSections :
|
||||||
{ label : String -> Element msg
|
{ label : String -> Element msg
|
||||||
, fromString : String -> Maybe elem
|
, fromString : String -> Maybe section
|
||||||
, msgMapper : Msg elem -> msg
|
, msgMapper : Msg section -> msg
|
||||||
, attributes : Bool -> List (Attribute msg)
|
, attributes : Bool -> List (Attribute msg)
|
||||||
}
|
}
|
||||||
-> Model elem
|
-> Model section
|
||||||
->
|
->
|
||||||
{ selected : Maybe elem
|
{ selected : Maybe section
|
||||||
, options : List elem
|
, options : List section
|
||||||
, label : elem -> Element msg
|
, label : section -> Element msg
|
||||||
, onChange : elem -> msg
|
, onChange : section -> msg
|
||||||
, attributes : Bool -> List (Attribute msg)
|
, attributes : Bool -> List (Attribute msg)
|
||||||
}
|
}
|
||||||
viewSections { label, fromString, msgMapper, attributes } { arrangement, scrollPos, labels, positions } =
|
viewSections { label, fromString, msgMapper, attributes } { arrangement, scrollPos, labels, positions } =
|
||||||
@ -177,8 +179,8 @@ viewSections { label, fromString, msgMapper, attributes } { arrangement, scrollP
|
|||||||
|
|
||||||
{-| -}
|
{-| -}
|
||||||
view :
|
view :
|
||||||
(elem -> Element msg)
|
(section -> Element msg)
|
||||||
-> Model elem
|
-> Model section
|
||||||
-> Element msg
|
-> Element msg
|
||||||
view asElement { labels, arrangement } =
|
view asElement { labels, arrangement } =
|
||||||
arrangement
|
arrangement
|
||||||
|
@ -34,7 +34,8 @@ type Model err a
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
{-| -}
|
{-| returns the raw value (the value that the user currently sees)
|
||||||
|
-}
|
||||||
getRaw : Model err a -> String
|
getRaw : Model err a -> String
|
||||||
getRaw (Model { raw, value, toString }) =
|
getRaw (Model { raw, value, toString }) =
|
||||||
case raw of
|
case raw of
|
||||||
@ -45,13 +46,15 @@ getRaw (Model { raw, value, toString }) =
|
|||||||
value |> toString
|
value |> toString
|
||||||
|
|
||||||
|
|
||||||
{-| -}
|
{-| returns the value (the value that has been last successfully validated)
|
||||||
|
-}
|
||||||
getValue : Model err a -> a
|
getValue : Model err a -> a
|
||||||
getValue (Model { value }) =
|
getValue (Model { value }) =
|
||||||
value
|
value
|
||||||
|
|
||||||
|
|
||||||
{-| -}
|
{-| returns the error (if one exists)
|
||||||
|
-}
|
||||||
getError : Model err a -> Maybe err
|
getError : Model err a -> Maybe err
|
||||||
getError (Model { err }) =
|
getError (Model { err }) =
|
||||||
err
|
err
|
||||||
@ -64,7 +67,13 @@ type Msg
|
|||||||
| StartEditing
|
| StartEditing
|
||||||
|
|
||||||
|
|
||||||
{-| -}
|
{-| The initial state contains
|
||||||
|
|
||||||
|
- `value`: starting value
|
||||||
|
- `validator`: a vaidation function (a decoder)
|
||||||
|
- `toString`: a function that returns a string representation
|
||||||
|
|
||||||
|
-}
|
||||||
init : { value : a, validator : String -> Result err a, toString : a -> String } -> Model err a
|
init : { value : a, validator : String -> Result err a, toString : a -> String } -> Model err a
|
||||||
init { validator, toString, value } =
|
init { validator, toString, value } =
|
||||||
Model
|
Model
|
||||||
@ -116,7 +125,15 @@ update msg (Model model) =
|
|||||||
Model model
|
Model model
|
||||||
|
|
||||||
|
|
||||||
{-| -}
|
{-| the view function, the parameters include
|
||||||
|
|
||||||
|
- `msgMapper`: A function wrapping the `Msg` into a `msg`
|
||||||
|
- `placeholder`: See Element.text for more information
|
||||||
|
- `label`: The (hidden) label of the input (needed for screen readers)
|
||||||
|
- `readOnly`: a representation of the validated value
|
||||||
|
(clicking on the element will turn on edit mode)
|
||||||
|
|
||||||
|
-}
|
||||||
view :
|
view :
|
||||||
List (Attribute msg)
|
List (Attribute msg)
|
||||||
-> Model err a
|
-> Model err a
|
||||||
|
Loading…
Reference in New Issue
Block a user