Last touches

This commit is contained in:
Unknown 2020-03-21 19:19:02 +01:00
parent a5d03e6d26
commit 3a7eaff6c6
7 changed files with 453 additions and 337 deletions

View File

@ -1,9 +1,9 @@
module Component exposing (Model,Msg(..),init,update,view)
module Component exposing (Model, Msg(..), init, update, view)
import Browser
import Element exposing (Element,Color)
import Element.Input as Input
import Element exposing (Color, Element)
import Element.Background as Background
import Element.Input as Input
import Framework
import Framework.Button as Button
import Framework.Card as Card
@ -13,64 +13,65 @@ import Framework.Group as Group
import Framework.Heading as Heading
import Framework.Input as Input
import Framework.Tag as Tag
import Heroicons.Solid as Heroicons
import Html exposing (Html)
import Html.Attributes as Attributes
import Set exposing (Set)
import Time
import Widget
import Widget.FilterSelect as FilterSelect
import Widget.ScrollingNav as ScrollingNav
import Widget.ValidatedInput as ValidatedInput
import Widget.Snackbar as Snackbar
import Time
import Heroicons.Solid as Heroicons
import Widget.ValidatedInput as ValidatedInput
type alias Model =
{ filterSelect : FilterSelect.Model
, validatedInput : ValidatedInput.Model () (( String, String ))
, validatedInput : ValidatedInput.Model () ( String, String )
}
type Msg
= FilterSelectSpecific FilterSelect.Msg
| ValidatedInputSpecific ValidatedInput.Msg
init : Model
init =
init : Model
init =
{ filterSelect =
[ "Apple"
, "Kiwi"
, "Strawberry"
, "Pineapple"
, "Mango"
, "Grapes"
, "Watermelon"
, "Orange"
, "Lemon"
, "Blueberry"
, "Grapefruit"
, "Coconut"
, "Cherry"
, "Banana"
]
|> Set.fromList
|> FilterSelect.init
, validatedInput =
ValidatedInput.init
{ value = ("John","Doe")
, validator =
\string ->
case string |> String.split " " of
[ first, second ] ->
Ok (( first, second ))
[ "Apple"
, "Kiwi"
, "Strawberry"
, "Pineapple"
, "Mango"
, "Grapes"
, "Watermelon"
, "Orange"
, "Lemon"
, "Blueberry"
, "Grapefruit"
, "Coconut"
, "Cherry"
, "Banana"
]
|> Set.fromList
|> FilterSelect.init
, validatedInput =
ValidatedInput.init
{ value = ( "John", "Doe" )
, validator =
\string ->
case string |> String.split " " of
[ first, second ] ->
Ok ( first, second )
_ ->
Err ()
, toString =
\( first, second ) -> first ++ " " ++ second
}
}
_ ->
Err ()
, toString =
(\( first, second ) -> first ++ " " ++ second)
}
}
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
@ -89,6 +90,7 @@ update msg model =
, Cmd.none
)
filterSelect : FilterSelect.Model -> Element Msg
filterSelect model =
Element.column (Grid.simple ++ Card.large) <|
@ -99,7 +101,7 @@ filterSelect model =
[ Element.el (Tag.simple ++ Group.left) <| Element.text <| selected
, Input.button (Tag.simple ++ Group.right ++ Color.danger)
{ 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
model
{ msgMapper = FilterSelectSpecific
, placeholder = Just <| Input.placeholder [] <| Element.text <|
"Fruit"
, placeholder =
Just <|
Input.placeholder [] <|
Element.text <|
"Fruit"
, label = "Fruit"
}
, model
@ -123,11 +128,10 @@ filterSelect model =
)
|> Element.wrappedRow [ Element.spacing 10 ]
]
]
validatedInput : ValidatedInput.Model () ( ( String, String )) -> Element Msg
validatedInput : ValidatedInput.Model () ( String, String ) -> Element Msg
validatedInput model =
Element.column (Grid.simple ++ Card.large) <|
[ Element.el Heading.h3 <| Element.text "Validated Input"
@ -136,44 +140,42 @@ validatedInput model =
{ label = "First Name, Sir Name"
, msgMapper = ValidatedInputSpecific
, placeholder = Nothing
, readOnly = \maybeTuple ->
Element.row Grid.compact
[ maybeTuple
|> (\(a,b) -> a ++ " " ++ b)
|> Element.text
|> Element.el (Tag.simple ++ Group.left)
, Heroicons.pencil [Attributes.width 16]
|> Element.html
|>Element.el (Tag.simple ++ Group.right ++ Color.primary)
]
, readOnly =
\maybeTuple ->
Element.row Grid.compact
[ maybeTuple
|> (\( a, b ) -> a ++ " " ++ b)
|> Element.text
|> Element.el (Tag.simple ++ Group.left)
, Heroicons.pencil [ Attributes.width 16 ]
|> Element.html
|> Element.el (Tag.simple ++ Group.right ++ Color.primary)
]
}
]
scrollingNavCard : Element msg
scrollingNavCard =
[Element.el Heading.h3 <| Element.text "Scrolling Nav"
scrollingNavCard =
[ Element.el Heading.h3 <| Element.text "Scrolling Nav"
, Element.text "Resize the screen and use the scrollbar to see the scrolling navigation in action."
|> List.singleton
|> Element.paragraph []
]
|> Element.column (Grid.simple ++ Card.large)
|> Element.column (Grid.simple ++ Card.large)
view : Model -> Element Msg
view model =
Element.column (Grid.section ++ [Element.centerX])
Element.column (Grid.section ++ [ Element.centerX ])
[ 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."
|> Element.text
|> List.singleton
|> Element.paragraph []
, Element.wrappedRow (Grid.simple ++ [Element.centerX])
<|
[ filterSelect model.filterSelect
, validatedInput model.validatedInput
, scrollingNavCard
, Element.wrappedRow (Grid.simple ++ [ Element.centerX ]) <|
[ filterSelect model.filterSelect
, validatedInput model.validatedInput
, scrollingNavCard
]
]
]

View File

@ -1,6 +1,7 @@
module Example exposing (main)
import Browser
import Component
import Element exposing (Element)
import Element.Input as Input
import Framework
@ -14,22 +15,23 @@ import Framework.Input as Input
import Framework.Tag as Tag
import Html exposing (Html)
import Html.Attributes as Attributes
import Reusable
import Set exposing (Set)
import Stateless
import Time
import Widget
import Widget.FilterSelect as FilterSelect
import Widget.ScrollingNav as ScrollingNav
import Widget.ValidatedInput as ValidatedInput
import Widget.Snackbar as Snackbar
import Stateless
import Reusable
import Component
import Time
import Widget.ValidatedInput as ValidatedInput
type Section
= ComponentViews
| ReusableViews
| StatelessViews
type alias Model =
{ component : Component.Model
, stateless : Stateless.Model
@ -39,6 +41,7 @@ type alias Model =
, displayDialog : Bool
}
type Msg
= StatelessSpecific Stateless.Msg
| ReusableSpecific Reusable.Msg
@ -59,6 +62,7 @@ init () =
case section of
ComponentViews ->
"Component Views"
ReusableViews ->
"Reusable Views"
@ -67,39 +71,37 @@ init () =
, arrangement = [ StatelessViews, ReusableViews, ComponentViews ]
}
in
({ component = Component.init
( { component = Component.init
, stateless = Stateless.init
, reusable = Reusable.init
, scrollingNav = scrollingNav
, snackbar = Snackbar.init
, displayDialog = False
}
, cmd |> Cmd.map ScrollingNavSpecific
)
view : Model -> Html Msg
view model =
[ Element.el [ Element.height <| Element.px <| 42 ] <| Element.none
, [ Element.el Heading.h1 <| Element.text "Elm-Ui-Widgets"
, model.scrollingNav
, model.scrollingNav
|> ScrollingNav.view
(\section ->
case section of
ComponentViews ->
model.component
|> Component.view
|> Element.map ComponentSpecific
|> Component.view
|> Element.map ComponentSpecific
ReusableViews ->
Reusable.view
{addSnackbar = AddSnackbar
,model = model.reusable
,msgMapper = ReusableSpecific
Reusable.view
{ addSnackbar = AddSnackbar
, model = model.reusable
, msgMapper = ReusableSpecific
}
StatelessViews ->
Stateless.view
{ msgMapper = StatelessSpecific
@ -107,7 +109,7 @@ view model =
}
model.stateless
)
]
]
|> Element.column Framework.container
]
|> Element.column Grid.compact
@ -120,6 +122,7 @@ view model =
case string of
"Component Views" ->
Just ComponentViews
"Reusable Views" ->
Just ReusableViews
@ -128,16 +131,18 @@ view model =
_ ->
Nothing
, label = Element.text
, label = Element.text
, msgMapper = ScrollingNavSpecific
, attributes = \selected -> Button.simple
++ Group.center
++ (if selected then
Color.primary
, attributes =
\selected ->
Button.simple
++ Group.center
++ (if selected then
Color.primary
else
Color.dark
)
else
Color.dark
)
}
|> Widget.select
|> Element.row
@ -157,38 +162,41 @@ view model =
)
)
, Element.inFront <|
( model.snackbar
(model.snackbar
|> Snackbar.current
|> Maybe.map
(Element.text >>
List.singleton >>
Element.paragraph (Card.simple ++ Color.dark)
>> Element.el [Element.padding 8,Element.alignBottom
, Element.alignRight]
(Element.text
>> List.singleton
>> Element.paragraph (Card.simple ++ Color.dark)
>> Element.el
[ Element.padding 8
, Element.alignBottom
, Element.alignRight
]
)
|> Maybe.withDefault Element.none
)
, Element.inFront <|
if model.displayDialog then
Widget.dialog {
onDismiss = Just <| ToggleDialog False
,content =
Widget.dialog
{ onDismiss = Just <| ToggleDialog False
, content =
[ Element.el Heading.h3 <| Element.text "Dialog"
, "This is a dialog window"
|> Element.text
|> List.singleton
|> Element.paragraph []
, Input.button (Button.simple ++ [Element.alignRight])
{onPress = Just <| ToggleDialog False
|> Element.text
|> List.singleton
|> Element.paragraph []
, Input.button (Button.simple ++ [ Element.alignRight ])
{ onPress = Just <| ToggleDialog False
, label = Element.text "Ok"
}
]
|>Element.column (Grid.simple ++ Card.large)
} else Element.none
|> Element.column (Grid.simple ++ Card.large)
}
else
Element.none
]
update : Msg -> Model -> ( Model, Cmd Msg )
@ -206,14 +214,16 @@ update msg model =
(Cmd.map ComponentSpecific)
ReusableSpecific m ->
(model.reusable
( model.reusable
|> Reusable.update m
|> (\reusable ->
{ model
| reusable = reusable
}
),Cmd.none)
)
, Cmd.none
)
StatelessSpecific m ->
model.stateless
|> Stateless.update m
@ -224,7 +234,6 @@ update msg model =
}
)
(Cmd.map StatelessSpecific)
ScrollingNavSpecific m ->
model.scrollingNav
@ -236,29 +245,32 @@ update msg model =
}
)
(Cmd.map ScrollingNavSpecific)
TimePassed int ->
({ model
| snackbar = model.snackbar |> Snackbar.timePassed int
},Cmd.none)
AddSnackbar string ->
( { model | snackbar = model.snackbar |> Snackbar.insert string}
( { model
| snackbar = model.snackbar |> Snackbar.timePassed int
}
, Cmd.none
)
ToggleDialog bool ->
( { model | displayDialog = bool }
, Cmd.none
AddSnackbar string ->
( { model | snackbar = model.snackbar |> Snackbar.insert string }
, Cmd.none
)
ToggleDialog bool ->
( { model | displayDialog = bool }
, Cmd.none
)
subscriptions : Model -> Sub Msg
subscriptions model=
subscriptions model =
Sub.batch
[ScrollingNav.subscriptions
|> Sub.map ScrollingNavSpecific
, Time.every 50 (always ( TimePassed 50))
]
[ ScrollingNav.subscriptions
|> Sub.map ScrollingNavSpecific
, Time.every 50 (always (TimePassed 50))
]
main : Program () Model Msg

View File

@ -1,9 +1,10 @@
module Reusable exposing (Model,Msg,init,view,update)
module Reusable exposing (Model, Msg, init, update, view)
import Browser
import Element exposing (Element,Color)
import Element.Input as Input
import Element exposing (Color, Element)
import Element.Background as Background
import Element.Font as Font
import Element.Input as Input
import Framework
import Framework.Button as Button
import Framework.Card as Card
@ -13,66 +14,73 @@ import Framework.Group as Group
import Framework.Heading as Heading
import Framework.Input as Input
import Framework.Tag as Tag
import Heroicons.Solid as Heroicons
import Html exposing (Html)
import Html.Attributes as Attributes
import Set exposing (Set)
import Time
import Widget
import Widget.FilterSelect as FilterSelect
import Widget.ScrollingNav as ScrollingNav
import Widget.ValidatedInput as ValidatedInput
import Widget.Snackbar as Snackbar
import Widget.SortTable as SortTable
import Time
import Heroicons.Solid as Heroicons
import Element.Font as Font
import Widget.ValidatedInput as ValidatedInput
type alias Model =
SortTable.Model
type Msg =
SortBy {title : String, asc : Bool }
type Msg
= SortBy { title : String, asc : Bool }
type alias Item =
{name : String
,amount : Int
,price : Float
{ name : String
, amount : Int
, price : Float
}
update : Msg -> Model -> Model
update msg model =
case msg of
SortBy m ->
m
init : Model
init =
SortTable.sortBy {title="Name",asc=True}
SortTable.sortBy { title = "Name", asc = True }
snackbar : (String -> msg) -> Element msg
snackbar addSnackbar =
[ Element.el Heading.h3 <| Element.text "Snackbar"
, Input.button Button.simple
{ onPress = Just <| addSnackbar "This is a notification. It will disappear after 10 seconds."
, label = "Add Notification"
|> Element.text
|> List.singleton
|> Element.paragraph []
, label =
"Add Notification"
|> Element.text
|> List.singleton
|> Element.paragraph []
}
]
|> Element.column (Grid.simple ++ Card.large)
|> Element.column (Grid.simple ++ Card.large)
sortTable : SortTable.Model -> Element Msg
sortTable model =
[ Element.el Heading.h3 <| Element.text "Sort Table"
, SortTable.view
{ content =
[ {id = 1, name = "Antonio", rating = 2.456}
, {id = 2, name = "Ana", rating = 1.34}
, {id = 3, name = "Alfred", rating = 4.22}
, {id = 4, name = "Thomas", rating = 3 }
[ { id = 1, name = "Antonio", rating = 2.456 }
, { id = 2, name = "Ana", rating = 1.34 }
, { id = 3, name = "Alfred", rating = 4.22 }
, { id = 4, name = "Thomas", rating = 3 }
]
, columns =
[ SortTable.intColumn
[ SortTable.intColumn
{ title = "Id"
, value = .id
, toString = \int -> "#" ++ String.fromInt int
@ -90,55 +98,66 @@ sortTable model =
]
, model = model
}
|> (\{data,columns} ->
{data = data
,columns = columns
|> List.map (\config->
{ header =
Input.button [Font.bold]
{ onPress = {title = config.header
,asc = if config.header == model.title then
not model.asc
else
True
}|> SortBy |> Just
, label =
if config.header == model.title then
[config.header |> Element.text
, Element.html <|if model.asc then
Heroicons.cheveronUp [Attributes.width 16]
else
Heroicons.cheveronDown [Attributes.width 16]
]
|> Element.row (Grid.simple ++ [Font.bold])
else
config.header |> Element.text
|> (\{ data, columns } ->
{ data = data
, columns =
columns
|> List.map
(\config ->
{ header =
Input.button [ Font.bold ]
{ onPress =
{ title = config.header
, asc =
if config.header == model.title then
not model.asc
else
True
}
|> SortBy
|> Just
, label =
if config.header == model.title then
[ config.header |> Element.text
, Element.html <|
if model.asc then
Heroicons.cheveronUp [ Attributes.width 16 ]
else
Heroicons.cheveronDown [ Attributes.width 16 ]
]
|> Element.row (Grid.simple ++ [ Font.bold ])
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.column (Grid.simple ++ Card.large)
|> Element.column (Grid.simple ++ Card.large)
view : { addSnackbar : String -> msg
view :
{ addSnackbar : String -> msg
, msgMapper : Msg -> msg
, model : Model } -> Element msg
view {addSnackbar,msgMapper,model} =
Element.column (Grid.section ++ [Element.centerX])
, model : Model
}
-> Element msg
view { addSnackbar, msgMapper, model } =
Element.column (Grid.section ++ [ Element.centerX ])
[ 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."
|> Element.text
|> List.singleton
|> Element.paragraph []
, Element.wrappedRow (Grid.simple ++ [Element.centerX])
<|
, Element.wrappedRow (Grid.simple ++ [ Element.centerX ]) <|
[ snackbar addSnackbar
, sortTable model |> Element.map msgMapper
]
]
]

View File

@ -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.Input as Input
import Element.Background as Background
import Element.Border as Border
import Set exposing (Set)
import Framework.Grid as Grid
import Element.Input as Input
import Framework.Button as Button
import Framework.Card as Card
import Framework.Color as Color
import Framework.Grid as Grid
import Framework.Group as Group
import Framework.Heading as Heading
import Framework.Input as Input
import Framework.Tag as Tag
import Heroicons.Solid as Heroicons
import Widget
import Heroicons.Solid as Heroicons
import Html exposing (Html)
import Html.Attributes as Attributes
import Array exposing (Array)
import Set exposing (Set)
import Widget
type alias Model =
{ selected : Maybe Int
@ -27,13 +28,15 @@ type alias Model =
, tab : Int
}
type Msg =
ChangedSelected Int
type Msg
= ChangedSelected Int
| ChangedMultiSelected Int
| ToggleCollapsable Bool
| ChangedTab Int
| SetCarousel Int
init : Model
init =
{ selected = Nothing
@ -43,8 +46,9 @@ init =
, tab = 1
}
update : Msg -> Model -> (Model,Cmd Msg)
update msg model =
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
ChangedSelected int ->
( { model
@ -52,36 +56,42 @@ update msg model =
}
, Cmd.none
)
ChangedMultiSelected int ->
( { model
| multiSelected =
model.multiSelected |>
if model.multiSelected |> Set.member int then
Set.remove int
else
Set.insert int
}
, Cmd.none )
| multiSelected =
model.multiSelected
|> (if model.multiSelected |> Set.member int then
Set.remove int
else
Set.insert int
)
}
, Cmd.none
)
ToggleCollapsable bool ->
( { model
( { model
| isCollapsed = bool
}
, Cmd.none)
}
, Cmd.none
)
SetCarousel int ->
( if (int < 0) || (int > 3) then
model
else
{model
| carousel = int
{ model
| carousel = int
}
, Cmd.none
)
ChangedTab int ->
( {model | tab = int }, Cmd.none )
( { model | tab = int }, Cmd.none )
select : Model -> Element Msg
select model =
@ -91,20 +101,40 @@ select model =
, options = [ 1, 2, 42 ]
, label = String.fromInt >> Element.text
, onChange = ChangedSelected
, attributes = \selected ->
Button.simple
++ Group.center
++ (if selected then
Color.primary
, attributes =
\selected ->
Button.simple
++ [ Border.width 0
, 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)
multiSelect : Model -> Element Msg
multiSelect model =
[ Element.el Heading.h3 <| Element.text "Multi Select"
@ -113,72 +143,100 @@ multiSelect model =
, options = [ 1, 2, 42 ]
, label = String.fromInt >> Element.text
, onChange = ChangedMultiSelected
, attributes = \selected ->
(Button.simple
++ Group.center
++ if selected then
Color.primary
, attributes =
\selected ->
Button.simple
++ [ Border.width 0
, 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.column (Grid.simple ++ Card.large)
collapsable : Model -> Element Msg
collapsable model =
[Element.el Heading.h3 <| Element.text "Collapsable"
,Widget.collapsable
{onToggle = ToggleCollapsable
,isCollapsed = model.isCollapsed
,label = Element.row Grid.compact
[ Element.html <|
if model.isCollapsed then
Heroicons.cheveronRight [ Attributes.width 20]
else
Heroicons.cheveronDown [ Attributes.width 20]
, Element.el Heading.h4 <|Element.text <| "Title"
]
,content = Element.text <| "Hello World"
[ Element.el Heading.h3 <| Element.text "Collapsable"
, Widget.collapsable
{ onToggle = ToggleCollapsable
, isCollapsed = model.isCollapsed
, label =
Element.row Grid.compact
[ Element.html <|
if model.isCollapsed then
Heroicons.cheveronRight [ Attributes.width 20 ]
else
Heroicons.cheveronDown [ Attributes.width 20 ]
, 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.el Heading.h3 <| Element.text "Tab"
,Widget.tab Grid.simple
[ Element.el Heading.h3 <| Element.text "Tab"
, Widget.tab Grid.simple
{ selected = model.tab
, options = [1,2,3]
, options = [ 1, 2, 3 ]
, onChange = ChangedTab
, label = \int -> "Tab " ++ String.fromInt int |> Element.text
, content = \selected ->
(case selected of
1 ->
"This is Tab 1"
2 ->
"This is the second tab"
3 ->
"The thrid and last tab"
_ ->
"Please select a tab"
, content =
\selected ->
(case selected of
1 ->
"This is Tab 1"
2 ->
"This is the second tab"
3 ->
"The thrid and last tab"
_ ->
"Please select a tab"
)
|>Element.text
|> Element.el (Card.small ++ Group.bottom)
, attributes = \selected ->
(Button.simple
++ Group.top
++ if selected then
Color.primary
else
[]
)
|> Element.text
|> Element.el (Card.small ++ Group.bottom)
, attributes =
\selected ->
Button.simple
++ Group.top
++ (if selected then
Color.primary
else
[]
)
}
]
|> Element.column (Grid.simple ++ Card.large)
|> Element.column (Grid.simple ++ Card.large)
dialog : msg -> Model -> Element msg
@ -189,42 +247,48 @@ dialog showDialog model =
, label = Element.text <| "Show Dialog"
}
]
|> Element.column (Grid.simple ++ Card.large)
|> Element.column (Grid.simple ++ Card.large)
carousel : Model -> Element Msg
carousel model =
[ Element.el Heading.h3 <| Element.text "Carousel"
, Widget.carousel
{content = (Color.cyan,[Color.yellow, Color.green , Color.red ]|> Array.fromList)
,current = model.carousel
, label = \c ->
[ Input.button [Element.centerY]
{ content = ( Color.cyan, [ Color.yellow, Color.green, Color.red ] |> Array.fromList )
, current = model.carousel
, label =
\c ->
[ Input.button [ Element.centerY ]
{ onPress = Just <| SetCarousel <| model.carousel - 1
, label = Heroicons.cheveronLeft [Attributes.width 20]
|> Element.html
, label =
Heroicons.cheveronLeft [ Attributes.width 20 ]
|> Element.html
}
, Element.el
, Element.el
(Card.simple
++ [ Background.color <| c
, Element.height <| Element.px <| 100
, Element.width <| Element.px <| 100
]
) <| Element.none
, Input.button [Element.centerY]
++ [ Background.color <| c
, Element.height <| Element.px <| 100
, Element.width <| Element.px <| 100
]
)
<|
Element.none
, Input.button [ Element.centerY ]
{ onPress = Just <| SetCarousel <| model.carousel + 1
, label = Heroicons.cheveronRight [Attributes.width 20]
|> Element.html
, label =
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,showDialog} model =
Element.column (Grid.section)
view : { msgMapper : Msg -> msg, showDialog : msg } -> Model -> Element msg
view { msgMapper, showDialog } model =
Element.column Grid.section
[ Element.el Heading.h2 <| Element.text "Stateless Views"
, "Stateless views are simple functions that view some content. No wiring required."
|> Element.text
@ -232,7 +296,7 @@ view {msgMapper,showDialog} model =
|> Element.paragraph []
, Element.wrappedRow
Grid.simple
<|
<|
[ select model |> Element.map msgMapper
, multiSelect model |> Element.map msgMapper
, collapsable model |> Element.map msgMapper
@ -240,4 +304,4 @@ view {msgMapper,showDialog} model =
, carousel model |> Element.map msgMapper
, tab model |> Element.map msgMapper
]
]
]

View File

@ -11,7 +11,7 @@ import Element.Input as Input exposing (Placeholder)
import Set exposing (Set)
{-| The Model
{-| The Model containing the raw value, the selected value and all the possible options.
-}
type alias Model =
{ raw : String

View File

@ -28,29 +28,30 @@ import Time
{-| -}
type alias Model elem =
{ labels : elem -> String
type alias Model section =
{ labels : section -> String
, positions : IntDict String
, arrangement : List elem
, arrangement : List section
, scrollPos : Int
}
{-| -}
type Msg elem
= GotHeaderPos elem (Result Dom.Error Int)
type Msg section
= GotHeaderPos section (Result Dom.Error Int)
| ChangedViewport (Result Dom.Error ())
| SyncPosition Int
| JumpTo elem
| JumpTo section
| TimePassed
{-| -}
{-| The intial state include the labels and the arrangement of the sections
-}
init :
{ labels : elem -> String
, arrangement : List elem
{ labels : section -> String
, arrangement : List section
}
-> ( Model elem, Cmd (Msg elem) )
-> ( Model section, Cmd (Msg section) )
init { labels, arrangement } =
{ labels = labels
, 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 =
case msg of
GotHeaderPos label result ->
@ -113,8 +114,9 @@ subscriptions =
Time.every 1000 (always TimePassed)
{-| -}
jumpTo : elem -> Model elem -> Cmd (Msg msg)
{-| scrolls the screen to the respective section
-}
jumpTo : section -> Model section -> Cmd (Msg msg)
jumpTo section { labels } =
Dom.getElement (section |> labels)
|> Task.andThen
@ -125,7 +127,7 @@ jumpTo section { labels } =
{-| -}
syncPositions : Model elem -> Cmd (Msg elem)
syncPositions : Model section -> Cmd (Msg section)
syncPositions { labels, arrangement } =
arrangement
|> List.map
@ -145,16 +147,16 @@ syncPositions { labels, arrangement } =
{-| -}
viewSections :
{ label : String -> Element msg
, fromString : String -> Maybe elem
, msgMapper : Msg elem -> msg
, fromString : String -> Maybe section
, msgMapper : Msg section -> msg
, attributes : Bool -> List (Attribute msg)
}
-> Model elem
-> Model section
->
{ selected : Maybe elem
, options : List elem
, label : elem -> Element msg
, onChange : elem -> msg
{ selected : Maybe section
, options : List section
, label : section -> Element msg
, onChange : section -> msg
, attributes : Bool -> List (Attribute msg)
}
viewSections { label, fromString, msgMapper, attributes } { arrangement, scrollPos, labels, positions } =
@ -177,8 +179,8 @@ viewSections { label, fromString, msgMapper, attributes } { arrangement, scrollP
{-| -}
view :
(elem -> Element msg)
-> Model elem
(section -> Element msg)
-> Model section
-> Element msg
view asElement { labels, arrangement } =
arrangement

View File

@ -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 { raw, value, toString }) =
case raw of
@ -45,13 +46,15 @@ getRaw (Model { raw, value, toString }) =
value |> toString
{-| -}
{-| returns the value (the value that has been last successfully validated)
-}
getValue : Model err a -> a
getValue (Model { value }) =
value
{-| -}
{-| returns the error (if one exists)
-}
getError : Model err a -> Maybe err
getError (Model { err }) =
err
@ -64,7 +67,13 @@ type Msg
| 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 { validator, toString, value } =
Model
@ -116,7 +125,15 @@ update msg (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 :
List (Attribute msg)
-> Model err a