mirror of
https://github.com/Orasund/elm-ui-widgets.git
synced 2024-11-22 22:33:33 +03:00
Moving Examples into own folder
This commit is contained in:
parent
732a18720d
commit
bc2c86257f
@ -17,6 +17,7 @@
|
||||
"feathericons/elm-feather": "1.4.0",
|
||||
"jasonliang512/elm-heroicons": "1.0.2",
|
||||
"mdgriffith/elm-ui": "1.1.5",
|
||||
"ryannhg/elm-spa": "4.1.0",
|
||||
"turboMaCk/queue": "1.0.2",
|
||||
"wernerdegroot/listzipper": "4.0.0"
|
||||
},
|
||||
|
187
example/src/Data/Example.elm
Normal file
187
example/src/Data/Example.elm
Normal file
@ -0,0 +1,187 @@
|
||||
module Data.Example exposing (Model, Msg, init, subscriptions, toCardList, update, view)
|
||||
|
||||
import Data.Style exposing (Style)
|
||||
import Element exposing (Element)
|
||||
import Example.Button as Button
|
||||
import Example.ExpansionPanel as ExpansionPanel
|
||||
import Example.MultiSelect as MultiSelect
|
||||
import Example.Select as Select
|
||||
import Example.Tab as Tab
|
||||
import Framework.Grid as Grid
|
||||
import View.Test as Test
|
||||
|
||||
|
||||
type Msg
|
||||
= Button Button.Msg
|
||||
| Select Select.Msg
|
||||
| MultiSelect MultiSelect.Msg
|
||||
| ExpansionPanel ExpansionPanel.Msg
|
||||
| Tab Tab.Msg
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ button : Button.Model
|
||||
, select : Select.Model
|
||||
, multiSelect : MultiSelect.Model
|
||||
, expansionPanel : ExpansionPanel.Model
|
||||
, tab : Tab.Model
|
||||
}
|
||||
|
||||
|
||||
init : ( Model, Cmd Msg )
|
||||
init =
|
||||
let
|
||||
( buttonModel, buttonMsg ) =
|
||||
Button.init
|
||||
|
||||
( selectModel, selectMsg ) =
|
||||
Select.init
|
||||
|
||||
( multiSelectModel, multiSelectMsg ) =
|
||||
MultiSelect.init
|
||||
|
||||
( expansionPanelModel, expansionPanelMsg ) =
|
||||
ExpansionPanel.init
|
||||
|
||||
( tabModel, tabMsg ) =
|
||||
Tab.init
|
||||
in
|
||||
( { button = buttonModel
|
||||
, select = selectModel
|
||||
, multiSelect = multiSelectModel
|
||||
, expansionPanel = expansionPanelModel
|
||||
, tab = tabModel
|
||||
}
|
||||
, [ Cmd.map Button buttonMsg
|
||||
, Cmd.map Select selectMsg
|
||||
, Cmd.map MultiSelect multiSelectMsg
|
||||
, Cmd.map Tab tabMsg
|
||||
]
|
||||
|> Cmd.batch
|
||||
)
|
||||
|
||||
|
||||
update : Msg -> Model -> ( Model, Cmd Msg )
|
||||
update msg model =
|
||||
case msg of
|
||||
Button buttonMsg ->
|
||||
Button.update buttonMsg model.button
|
||||
|> Tuple.mapBoth
|
||||
(\a -> { model | button = a })
|
||||
(Cmd.map Button)
|
||||
|
||||
Select selectMsg ->
|
||||
Select.update selectMsg model.select
|
||||
|> Tuple.mapBoth
|
||||
(\a -> { model | select = a })
|
||||
(Cmd.map Select)
|
||||
|
||||
MultiSelect multiSelectMsg ->
|
||||
MultiSelect.update multiSelectMsg model.multiSelect
|
||||
|> Tuple.mapBoth
|
||||
(\a -> { model | multiSelect = a })
|
||||
(Cmd.map MultiSelect)
|
||||
|
||||
ExpansionPanel expansionPanelMsg ->
|
||||
ExpansionPanel.update expansionPanelMsg model.expansionPanel
|
||||
|> Tuple.mapBoth
|
||||
(\a -> { model | expansionPanel = a })
|
||||
(Cmd.map ExpansionPanel)
|
||||
|
||||
Tab tabMsg ->
|
||||
Tab.update tabMsg model.tab
|
||||
|> Tuple.mapBoth
|
||||
(\a -> { model | tab = a })
|
||||
(Cmd.map Tab)
|
||||
|
||||
|
||||
subscriptions : Model -> Sub Msg
|
||||
subscriptions model =
|
||||
[ Button.subscriptions model.button |> Sub.map Button
|
||||
, Select.subscriptions model.select |> Sub.map Select
|
||||
, MultiSelect.subscriptions model.multiSelect |> Sub.map MultiSelect
|
||||
, ExpansionPanel.subscriptions model.expansionPanel |> Sub.map ExpansionPanel
|
||||
, Tab.subscriptions model.tab |> Sub.map Tab
|
||||
]
|
||||
|> Sub.batch
|
||||
|
||||
|
||||
view :
|
||||
(Msg -> msg)
|
||||
-> Style msg
|
||||
-> Model
|
||||
->
|
||||
{ button : Element msg
|
||||
, select : Element msg
|
||||
, multiSelect : Element msg
|
||||
, expansionPanel : Element msg
|
||||
, tab : Element msg
|
||||
}
|
||||
view msgMapper style model =
|
||||
{ button =
|
||||
Button.view
|
||||
(Button >> msgMapper)
|
||||
style
|
||||
model.button
|
||||
, select =
|
||||
Select.view
|
||||
(Select >> msgMapper)
|
||||
style
|
||||
model.select
|
||||
, multiSelect =
|
||||
MultiSelect.view
|
||||
(MultiSelect >> msgMapper)
|
||||
style
|
||||
model.multiSelect
|
||||
, expansionPanel =
|
||||
ExpansionPanel.view
|
||||
(ExpansionPanel >> msgMapper)
|
||||
style
|
||||
model.expansionPanel
|
||||
, tab =
|
||||
Tab.view
|
||||
(Tab >> msgMapper)
|
||||
style
|
||||
model.tab
|
||||
}
|
||||
|
||||
|
||||
toCardList :
|
||||
{ idle : msg
|
||||
, msgMapper : Msg -> msg
|
||||
, style : Style msg
|
||||
, model : Model
|
||||
}
|
||||
-> List ( String, Element msg, Element msg )
|
||||
toCardList { idle, msgMapper, style, model } =
|
||||
[ { title = "Icon Button"
|
||||
, example = .button
|
||||
, test = Test.iconButton
|
||||
}
|
||||
, { title = "Select"
|
||||
, example = .select
|
||||
, test = Test.select
|
||||
}
|
||||
, { title = "Multi Select"
|
||||
, example = .multiSelect
|
||||
, test = Test.multiSelect
|
||||
}
|
||||
, { title = "Expansion Panel"
|
||||
, example = .expansionPanel
|
||||
, test = Test.expansionPanel
|
||||
}
|
||||
, { title = "Tab"
|
||||
, example = .tab
|
||||
, test = Test.tab
|
||||
}
|
||||
]
|
||||
|> List.map
|
||||
(\{ title, example, test } ->
|
||||
( title
|
||||
, model
|
||||
|> view msgMapper style
|
||||
|> example
|
||||
, test idle style
|
||||
|> Element.column Grid.simple
|
||||
)
|
||||
)
|
@ -29,7 +29,7 @@ textButton =
|
||||
|
||||
simpleButton : ButtonStyle msg
|
||||
simpleButton =
|
||||
{ container = Button.simple ++ Color.primary
|
||||
{ container = Button.simple ++ Color.success
|
||||
, labelRow = Grid.simple
|
||||
, ifDisabled = Color.disabled
|
||||
, ifActive = Color.primary
|
||||
@ -211,7 +211,7 @@ row =
|
||||
|
||||
cardColumn : ColumnStyle msg
|
||||
cardColumn =
|
||||
{ containerColumn = Grid.compact
|
||||
{ containerColumn = Grid.compact ++ [Element.height <| Element.fill]
|
||||
, element = Card.large ++ [Element.height <| Element.fill]
|
||||
, ifFirst = Group.top
|
||||
, ifLast = Group.bottom
|
||||
|
83
example/src/Example/Button.elm
Normal file
83
example/src/Example/Button.elm
Normal file
@ -0,0 +1,83 @@
|
||||
module Example.Button exposing (Model, Msg, init, subscriptions, update, view)
|
||||
|
||||
import Element exposing (Element)
|
||||
import FeatherIcons
|
||||
import Widget
|
||||
import Widget.Style exposing (ButtonStyle)
|
||||
|
||||
|
||||
type alias Style style msg =
|
||||
{ style
|
||||
| primaryButton : ButtonStyle msg
|
||||
, button : ButtonStyle msg
|
||||
}
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ isButtonEnabled : Bool
|
||||
}
|
||||
|
||||
|
||||
type Msg
|
||||
= ChangedButtonStatus Bool
|
||||
|
||||
|
||||
init : ( Model, Cmd Msg )
|
||||
init =
|
||||
( { isButtonEnabled = True
|
||||
}
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
|
||||
update : Msg -> Model -> ( Model, Cmd Msg )
|
||||
update msg model =
|
||||
case msg of
|
||||
ChangedButtonStatus bool ->
|
||||
( { model | isButtonEnabled = bool }
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
|
||||
subscriptions : Model -> Sub Msg
|
||||
subscriptions _ =
|
||||
Sub.none
|
||||
|
||||
|
||||
view : (Msg -> msg) -> Style style msg -> Model -> Element msg
|
||||
view msgMapper style model =
|
||||
[ Widget.button style.primaryButton
|
||||
{ text = "disable me"
|
||||
, icon =
|
||||
FeatherIcons.slash
|
||||
|> FeatherIcons.withSize 16
|
||||
|> FeatherIcons.toHtml []
|
||||
|> Element.html
|
||||
|> Element.el []
|
||||
, onPress =
|
||||
if model.isButtonEnabled then
|
||||
ChangedButtonStatus False
|
||||
|> msgMapper
|
||||
|> Just
|
||||
|
||||
else
|
||||
Nothing
|
||||
}
|
||||
, Widget.iconButton style.button
|
||||
{ text = "reset"
|
||||
, icon =
|
||||
FeatherIcons.repeat
|
||||
|> FeatherIcons.withSize 16
|
||||
|> FeatherIcons.toHtml []
|
||||
|> Element.html
|
||||
|> Element.el []
|
||||
, onPress =
|
||||
ChangedButtonStatus True
|
||||
|> msgMapper
|
||||
|> Just
|
||||
}
|
||||
]
|
||||
|> Element.row
|
||||
[ Element.spaceEvenly
|
||||
, Element.width <| Element.fill
|
||||
]
|
53
example/src/Example/ExpansionPanel.elm
Normal file
53
example/src/Example/ExpansionPanel.elm
Normal file
@ -0,0 +1,53 @@
|
||||
module Example.ExpansionPanel exposing (Model, Msg, init, subscriptions, update, view)
|
||||
|
||||
import Element exposing (Element)
|
||||
import Widget
|
||||
import Widget.Style exposing (ExpansionPanelStyle)
|
||||
|
||||
|
||||
type alias Style style msg =
|
||||
{ style
|
||||
| expansionPanel : ExpansionPanelStyle msg
|
||||
}
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ isExpanded : Bool }
|
||||
|
||||
|
||||
type Msg
|
||||
= ToggleCollapsable Bool
|
||||
|
||||
|
||||
init : ( Model, Cmd Msg )
|
||||
init =
|
||||
( { isExpanded = False }
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
|
||||
update : Msg -> Model -> ( Model, Cmd Msg )
|
||||
update msg model =
|
||||
case msg of
|
||||
ToggleCollapsable bool ->
|
||||
( { model
|
||||
| isExpanded = bool
|
||||
}
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
|
||||
subscriptions : Model -> Sub Msg
|
||||
subscriptions _ =
|
||||
Sub.none
|
||||
|
||||
|
||||
view : (Msg -> msg) -> Style style msg -> Model -> Element msg
|
||||
view msgMapper style model =
|
||||
{ onToggle = ToggleCollapsable >> msgMapper
|
||||
, isExpanded = model.isExpanded
|
||||
, icon = Element.none
|
||||
, text = "Title"
|
||||
, content = Element.text <| "Hello World"
|
||||
}
|
||||
|> Widget.expansionPanel style.expansionPanel
|
72
example/src/Example/MultiSelect.elm
Normal file
72
example/src/Example/MultiSelect.elm
Normal file
@ -0,0 +1,72 @@
|
||||
module Example.MultiSelect exposing (Model, Msg, init, subscriptions, update, view)
|
||||
|
||||
import Element exposing (Element)
|
||||
import Set exposing (Set)
|
||||
import Widget
|
||||
import Widget.Style exposing (ButtonStyle, RowStyle)
|
||||
|
||||
|
||||
type alias Style style msg =
|
||||
{ style
|
||||
| row : RowStyle msg
|
||||
, button : ButtonStyle msg
|
||||
}
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ selected : Set Int
|
||||
}
|
||||
|
||||
|
||||
type Msg
|
||||
= ChangedSelected Int
|
||||
|
||||
|
||||
init : ( Model, Cmd Msg )
|
||||
init =
|
||||
( { selected = Set.empty }
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
|
||||
update : Msg -> Model -> ( Model, Cmd Msg )
|
||||
update msg model =
|
||||
case msg of
|
||||
ChangedSelected int ->
|
||||
( { model
|
||||
| selected =
|
||||
model.selected
|
||||
|> (if model.selected |> Set.member int then
|
||||
Set.remove int
|
||||
|
||||
else
|
||||
Set.insert int
|
||||
)
|
||||
}
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
|
||||
subscriptions : Model -> Sub Msg
|
||||
subscriptions _ =
|
||||
Sub.none
|
||||
|
||||
|
||||
view : (Msg -> msg) -> Style style msg -> Model -> Element msg
|
||||
view msgMapper style model =
|
||||
{ selected = model.selected
|
||||
, options =
|
||||
[ 1, 2, 42 ]
|
||||
|> List.map
|
||||
(\int ->
|
||||
{ text = String.fromInt int
|
||||
, icon = Element.none
|
||||
}
|
||||
)
|
||||
, onSelect = ChangedSelected >> msgMapper >> Just
|
||||
}
|
||||
|> Widget.multiSelect
|
||||
|> Widget.buttonRow
|
||||
{ list = style.row
|
||||
, button = style.button
|
||||
}
|
64
example/src/Example/Select.elm
Normal file
64
example/src/Example/Select.elm
Normal file
@ -0,0 +1,64 @@
|
||||
module Example.Select exposing (Model, Msg, init, subscriptions, update, view)
|
||||
|
||||
import Element exposing (Attribute, Element)
|
||||
import FeatherIcons
|
||||
import Widget
|
||||
import Widget.Style exposing (ButtonStyle, RowStyle)
|
||||
|
||||
|
||||
type alias Style style msg =
|
||||
{ style
|
||||
| row : RowStyle msg
|
||||
, button : ButtonStyle msg
|
||||
}
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ selected : Maybe Int }
|
||||
|
||||
|
||||
type Msg
|
||||
= ChangedSelected Int
|
||||
|
||||
|
||||
init : ( Model, Cmd Msg )
|
||||
init =
|
||||
( { selected = Nothing }
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
|
||||
update : Msg -> Model -> ( Model, Cmd Msg )
|
||||
update msg model =
|
||||
case msg of
|
||||
ChangedSelected int ->
|
||||
( { model
|
||||
| selected = Just int
|
||||
}
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
|
||||
subscriptions : Model -> Sub Msg
|
||||
subscriptions _ =
|
||||
Sub.none
|
||||
|
||||
|
||||
view : (Msg -> msg) -> Style style msg -> Model -> Element msg
|
||||
view msgMapper style model =
|
||||
{ selected = model.selected
|
||||
, options =
|
||||
[ 1, 2, 42 ]
|
||||
|> List.map
|
||||
(\int ->
|
||||
{ text = String.fromInt int
|
||||
, icon = Element.none
|
||||
}
|
||||
)
|
||||
, onSelect = ChangedSelected >> msgMapper >> Just
|
||||
}
|
||||
|> Widget.select
|
||||
|> Widget.buttonRow
|
||||
{ list = style.row
|
||||
, button = style.button
|
||||
}
|
76
example/src/Example/Tab.elm
Normal file
76
example/src/Example/Tab.elm
Normal file
@ -0,0 +1,76 @@
|
||||
module Example.Tab exposing (Model, Msg, init, subscriptions, update, view)
|
||||
|
||||
import Element exposing (Element)
|
||||
import Widget
|
||||
import Widget.Style exposing (TabStyle)
|
||||
|
||||
|
||||
type alias Style style msg =
|
||||
{ style
|
||||
| tab : TabStyle msg
|
||||
}
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ selected : Maybe Int
|
||||
}
|
||||
|
||||
|
||||
type Msg
|
||||
= ChangedTab Int
|
||||
|
||||
|
||||
init : ( Model, Cmd Msg )
|
||||
init =
|
||||
( { selected = Nothing
|
||||
}
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
|
||||
update : Msg -> Model -> ( Model, Cmd Msg )
|
||||
update msg model =
|
||||
case msg of
|
||||
ChangedTab int ->
|
||||
( { model | selected = Just int }
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
|
||||
subscriptions : Model -> Sub Msg
|
||||
subscriptions _ =
|
||||
Sub.none
|
||||
|
||||
|
||||
view : (Msg -> msg) -> Style style msg -> Model -> Element msg
|
||||
view msgMapper style model =
|
||||
Widget.tab style.tab
|
||||
{ tabs =
|
||||
{ selected = model.selected
|
||||
, options =
|
||||
[ 1, 2, 3 ]
|
||||
|> List.map
|
||||
(\int ->
|
||||
{ text = "Tab " ++ (int |> String.fromInt)
|
||||
, icon = Element.none
|
||||
}
|
||||
)
|
||||
, onSelect = ChangedTab >> msgMapper >> Just
|
||||
}
|
||||
, content =
|
||||
\selected ->
|
||||
(case selected of
|
||||
Just 0 ->
|
||||
"This is Tab 1"
|
||||
|
||||
Just 1 ->
|
||||
"This is the second tab"
|
||||
|
||||
Just 2 ->
|
||||
"The thrid and last tab"
|
||||
|
||||
_ ->
|
||||
"Please select a tab"
|
||||
)
|
||||
|> Element.text
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
module Example exposing (main)
|
||||
module Main exposing (main)
|
||||
|
||||
import Array
|
||||
import Browser
|
||||
@ -6,6 +6,8 @@ import Browser.Dom as Dom exposing (Viewport)
|
||||
import Browser.Events as Events
|
||||
import Browser.Navigation as Navigation
|
||||
import Data.Section as Section exposing (Section(..))
|
||||
import Data.Style as Style exposing (Style)
|
||||
import Data.Theme as Theme exposing (Theme(..))
|
||||
import Element exposing (Attribute, DeviceClass(..), Element)
|
||||
import Element.Border as Border
|
||||
import Element.Font as Font
|
||||
@ -32,15 +34,10 @@ import Widget
|
||||
import Widget.ScrollingNav as ScrollingNav
|
||||
import Widget.Snackbar as Snackbar
|
||||
import Widget.Style exposing (ButtonStyle)
|
||||
import Data.Style as Style exposing (Style)
|
||||
import Data.Theme as Theme exposing (Theme(..))
|
||||
|
||||
|
||||
|
||||
|
||||
type alias LoadedModel =
|
||||
{ stateless : Stateless.Model
|
||||
, reusable : Reusable.Model
|
||||
, scrollingNav : ScrollingNav.Model Section
|
||||
, layout : Layout LoadedMsg
|
||||
, displayDialog : Bool
|
||||
@ -61,7 +58,6 @@ type Model
|
||||
|
||||
type LoadedMsg
|
||||
= StatelessSpecific Stateless.Msg
|
||||
| ReusableSpecific Reusable.Msg
|
||||
| UpdateScrollingNav (ScrollingNav.Model Section -> ScrollingNav.Model Section)
|
||||
| TimePassed Int
|
||||
| AddSnackbar ( String, Bool )
|
||||
@ -97,9 +93,11 @@ initialModel { viewport } =
|
||||
Err _ ->
|
||||
Idle
|
||||
}
|
||||
|
||||
( stateless, statelessCmd ) =
|
||||
Stateless.init
|
||||
in
|
||||
( { stateless = Stateless.init
|
||||
, reusable = Reusable.init
|
||||
( { stateless = stateless
|
||||
, scrollingNav = scrollingNav
|
||||
, layout = Layout.init
|
||||
, displayDialog = False
|
||||
@ -114,7 +112,10 @@ initialModel { viewport } =
|
||||
}
|
||||
, theme = ElmUiFramework
|
||||
}
|
||||
, cmd
|
||||
, [ cmd
|
||||
, statelessCmd |> Cmd.map StatelessSpecific
|
||||
]
|
||||
|> Cmd.batch
|
||||
)
|
||||
|
||||
|
||||
@ -127,7 +128,6 @@ init () =
|
||||
|
||||
view : Model -> Html Msg
|
||||
view model =
|
||||
|
||||
case model of
|
||||
Loading ->
|
||||
Element.none |> Framework.responsiveLayout []
|
||||
@ -173,8 +173,6 @@ view model =
|
||||
ReusableViews ->
|
||||
Reusable.view m.theme
|
||||
{ addSnackbar = AddSnackbar
|
||||
, model = m.reusable
|
||||
, msgMapper = ReusableSpecific
|
||||
}
|
||||
|
||||
StatelessViews ->
|
||||
@ -198,7 +196,7 @@ view model =
|
||||
, items
|
||||
|> (if m.search.current /= "" then
|
||||
List.filter
|
||||
(\(a,_,_) ->
|
||||
(\( a, _, _ ) ->
|
||||
a
|
||||
|> String.toLower
|
||||
|> String.contains (m.search.current |> String.toLower)
|
||||
@ -209,10 +207,13 @@ view model =
|
||||
)
|
||||
|> List.map
|
||||
(\( name, elem, more ) ->
|
||||
[ Element.text name
|
||||
|> Element.el Heading.h3
|
||||
[ [ Element.text name
|
||||
|> Element.el (Heading.h3 ++ [ Element.height <| Element.shrink ])
|
||||
, elem
|
||||
]
|
||||
|> Element.column Grid.simple
|
||||
, more
|
||||
|> Element.el [ Element.height <| Element.fill ]
|
||||
]
|
||||
|> Widget.column style.cardColumn
|
||||
)
|
||||
@ -226,7 +227,7 @@ view model =
|
||||
|> Element.column Framework.container
|
||||
]
|
||||
|> Element.column Grid.compact
|
||||
, style =style
|
||||
, style = style
|
||||
, layout = m.layout
|
||||
, window = m.window
|
||||
, menu =
|
||||
@ -247,15 +248,19 @@ view model =
|
||||
, text = "Github"
|
||||
, icon = Icons.github |> Element.html |> Element.el []
|
||||
}
|
||||
, { onPress = if m.theme /= ElmUiFramework then
|
||||
, { onPress =
|
||||
if m.theme /= ElmUiFramework then
|
||||
Just <| SetTheme <| ElmUiFramework
|
||||
|
||||
else
|
||||
Nothing
|
||||
, text = "Elm-Ui-Framework Theme"
|
||||
, icon = Icons.penTool |> Element.html |> Element.el []
|
||||
}
|
||||
, { onPress = if m.theme /= Template then
|
||||
, { onPress =
|
||||
if m.theme /= Template then
|
||||
Just <| SetTheme <| Template
|
||||
|
||||
else
|
||||
Nothing
|
||||
, text = "Template Theme"
|
||||
@ -291,17 +296,6 @@ view model =
|
||||
updateLoaded : LoadedMsg -> LoadedModel -> ( LoadedModel, Cmd LoadedMsg )
|
||||
updateLoaded msg model =
|
||||
case msg of
|
||||
ReusableSpecific m ->
|
||||
( model.reusable
|
||||
|> Reusable.update m
|
||||
|> (\reusable ->
|
||||
{ model
|
||||
| reusable = reusable
|
||||
}
|
||||
)
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
StatelessSpecific m ->
|
||||
model.stateless
|
||||
|> Stateless.update m
|
@ -1,4 +1,4 @@
|
||||
module Reusable exposing (Model, Msg, init, update, view)
|
||||
module Reusable exposing ( view)
|
||||
|
||||
import Browser
|
||||
import Element exposing (Color, Element)
|
||||
@ -22,17 +22,9 @@ import Time
|
||||
import Widget
|
||||
import Widget.ScrollingNav as ScrollingNav
|
||||
import Widget.Snackbar as Snackbar
|
||||
import Widget.SortTable as SortTable
|
||||
import Data.Style exposing (Style)
|
||||
import Data.Theme as Theme exposing (Theme)
|
||||
|
||||
type alias Model =
|
||||
SortTable.Model
|
||||
|
||||
|
||||
type Msg
|
||||
= SortBy { title : String, asc : Bool }
|
||||
|
||||
|
||||
type alias Item =
|
||||
{ name : String
|
||||
@ -41,17 +33,6 @@ type alias Item =
|
||||
}
|
||||
|
||||
|
||||
update : Msg -> Model -> Model
|
||||
update msg model =
|
||||
case msg of
|
||||
SortBy m ->
|
||||
m
|
||||
|
||||
|
||||
init : Model
|
||||
init =
|
||||
SortTable.sortBy { title = "Name", asc = True }
|
||||
|
||||
|
||||
snackbar : Style msg -> (( String, Bool ) -> msg) -> ( String, Element msg,Element msg )
|
||||
snackbar style addSnackbar =
|
||||
@ -82,78 +63,7 @@ snackbar style addSnackbar =
|
||||
)
|
||||
|
||||
|
||||
sortTable : Style Msg -> SortTable.Model -> ( String, Element Msg,Element Msg )
|
||||
sortTable style model =
|
||||
( "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 }
|
||||
]
|
||||
, columns =
|
||||
[ SortTable.intColumn
|
||||
{ title = "Id"
|
||||
, value = .id
|
||||
, toString = \int -> "#" ++ String.fromInt int
|
||||
}
|
||||
, SortTable.stringColumn
|
||||
{ title = "Name"
|
||||
, value = .name
|
||||
, toString = identity
|
||||
}
|
||||
, SortTable.floatColumn
|
||||
{ title = "rating"
|
||||
, value = .rating
|
||||
, toString = String.fromFloat
|
||||
}
|
||||
]
|
||||
, 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
|
||||
}
|
||||
, view = config.view >> Element.text
|
||||
, width = Element.fill
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|> Element.table Grid.simple
|
||||
, Element.none
|
||||
)
|
||||
|
||||
|
||||
scrollingNavCard : Style msg -> ( String, Element msg, Element msg )
|
||||
@ -169,15 +79,13 @@ scrollingNavCard style =
|
||||
view :
|
||||
Theme ->
|
||||
{ addSnackbar : ( String, Bool ) -> msg
|
||||
, msgMapper : Msg -> msg
|
||||
, model : Model
|
||||
}
|
||||
->
|
||||
{ title : String
|
||||
, description : String
|
||||
, items : List ( String, Element msg,Element msg )
|
||||
}
|
||||
view theme { addSnackbar, msgMapper, model } =
|
||||
view theme { addSnackbar } =
|
||||
let
|
||||
style = Theme.toStyle theme
|
||||
in
|
||||
@ -185,8 +93,6 @@ view theme { addSnackbar, msgMapper, model } =
|
||||
, description = "Reusable views have an internal state but no update function. You will need to do some wiring, but nothing complicated."
|
||||
, items =
|
||||
[ snackbar style addSnackbar
|
||||
, sortTable style model |> \(a,b,c) ->
|
||||
(a,b |> Element.map msgMapper,c |> Element.map msgMapper)
|
||||
, scrollingNavCard style
|
||||
]
|
||||
}
|
||||
|
@ -1,96 +1,66 @@
|
||||
module Stateless exposing (Model, Msg, init, update, view)
|
||||
|
||||
import Array exposing (Array)
|
||||
import Array
|
||||
import Data.Example as Example
|
||||
import Data.Style exposing (Style)
|
||||
import Data.Theme as Theme exposing (Theme)
|
||||
import Element exposing (Element)
|
||||
import Element.Background as Background
|
||||
import Element.Border as Border
|
||||
import Element.Font as Font
|
||||
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 Html exposing (Html)
|
||||
import Html.Attributes as Attributes
|
||||
import Icons
|
||||
import Layout exposing (Part(..))
|
||||
import Set exposing (Set)
|
||||
import Widget
|
||||
import Widget.Style exposing (ButtonStyle)
|
||||
import Data.Theme as Theme exposing (Theme)
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ selected : Maybe Int
|
||||
, multiSelected : Set Int
|
||||
, chipTextInput : Set String
|
||||
, isExpanded : Bool
|
||||
{ chipTextInput : Set String
|
||||
, carousel : Int
|
||||
, tab : Maybe Int
|
||||
, button : Bool
|
||||
, textInput : String
|
||||
, table : { title : String, asc : Bool }
|
||||
, example : Example.Model
|
||||
}
|
||||
|
||||
|
||||
type Msg
|
||||
= ChangedSelected Int
|
||||
| ChangedMultiSelected Int
|
||||
| ToggleCollapsable Bool
|
||||
| ToggleTextInputChip String
|
||||
| ChangedTab Int
|
||||
= ToggleTextInputChip String
|
||||
| SetCarousel Int
|
||||
| ToggleButton Bool
|
||||
| SetTextInput String
|
||||
| ChangedSorting String
|
||||
| ExampleSpecific Example.Msg
|
||||
| Idle
|
||||
|
||||
|
||||
init : Model
|
||||
init : ( Model, Cmd Msg )
|
||||
init =
|
||||
{ selected = Nothing
|
||||
, multiSelected = Set.empty
|
||||
, chipTextInput = Set.empty
|
||||
, isExpanded = False
|
||||
let
|
||||
( example, cmd ) =
|
||||
Example.init
|
||||
in
|
||||
( { chipTextInput = Set.empty
|
||||
, carousel = 0
|
||||
, tab = Just 1
|
||||
, button = True
|
||||
, textInput = ""
|
||||
, table = { title = "Name", asc = True }
|
||||
, example = example
|
||||
}
|
||||
, cmd |> Cmd.map ExampleSpecific
|
||||
)
|
||||
|
||||
|
||||
update : Msg -> Model -> ( Model, Cmd Msg )
|
||||
update msg model =
|
||||
case msg of
|
||||
ChangedSelected int ->
|
||||
( { model
|
||||
| selected = Just int
|
||||
}
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
ChangedMultiSelected int ->
|
||||
( { model
|
||||
| multiSelected =
|
||||
model.multiSelected
|
||||
|> (if model.multiSelected |> Set.member int then
|
||||
Set.remove int
|
||||
|
||||
else
|
||||
Set.insert int
|
||||
)
|
||||
}
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
ToggleCollapsable bool ->
|
||||
( { model
|
||||
| isExpanded = bool
|
||||
}
|
||||
, Cmd.none
|
||||
ExampleSpecific exampleMsg ->
|
||||
let
|
||||
( exampleModel, exampleCmd ) =
|
||||
Example.update exampleMsg model.example
|
||||
in
|
||||
( { model | example = exampleModel }
|
||||
, exampleCmd |> Cmd.map ExampleSpecific
|
||||
)
|
||||
|
||||
ToggleTextInputChip string ->
|
||||
@ -118,127 +88,30 @@ update msg model =
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
ChangedTab int ->
|
||||
( { model | tab = Just int }, Cmd.none )
|
||||
|
||||
ToggleButton bool ->
|
||||
( { model | button = bool }, Cmd.none )
|
||||
|
||||
SetTextInput string ->
|
||||
( { model | textInput = string }, Cmd.none )
|
||||
|
||||
ChangedSorting string ->
|
||||
( { model
|
||||
| table =
|
||||
{ title = string
|
||||
, asc =
|
||||
if model.table.title == string then
|
||||
not model.table.asc
|
||||
|
||||
else
|
||||
True
|
||||
}
|
||||
}
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
Idle ->
|
||||
( model, Cmd.none )
|
||||
|
||||
|
||||
select : Style Msg -> Model -> ( String, Element Msg,Element Msg )
|
||||
select style model =
|
||||
let
|
||||
buttonStyle =
|
||||
style.button
|
||||
in
|
||||
( "Select"
|
||||
, { selected = model.selected
|
||||
, options =
|
||||
[ 1, 2, 42 ]
|
||||
|> List.map
|
||||
(\int ->
|
||||
{ text = String.fromInt int
|
||||
, icon = Element.none
|
||||
}
|
||||
)
|
||||
, onSelect = ChangedSelected >> Just
|
||||
}
|
||||
|> Widget.select
|
||||
|> Widget.buttonRow
|
||||
{ list = style.row
|
||||
, button = style.button
|
||||
}
|
||||
, Element.none
|
||||
)
|
||||
|
||||
|
||||
multiSelect : Style Msg -> Model -> ( String, Element Msg, Element Msg )
|
||||
multiSelect style model =
|
||||
let
|
||||
buttonStyle =
|
||||
style.button
|
||||
in
|
||||
( "Multi Select"
|
||||
, { selected = model.multiSelected
|
||||
, options =
|
||||
[ 1, 2, 42 ]
|
||||
|> List.map
|
||||
(\int ->
|
||||
{ text = String.fromInt int
|
||||
, icon = Element.none
|
||||
}
|
||||
)
|
||||
, onSelect = ChangedMultiSelected >> Just
|
||||
}
|
||||
|> Widget.multiSelect
|
||||
|> Widget.buttonRow
|
||||
{ list = style.row
|
||||
, button = style.button
|
||||
}
|
||||
, Element.none
|
||||
)
|
||||
|
||||
expansionPanel : Style Msg -> Model -> (String,Element Msg,Element Msg)
|
||||
expansionPanel style model =
|
||||
( "Expansion Panel"
|
||||
, { onToggle = ToggleCollapsable
|
||||
, isExpanded = model.isExpanded
|
||||
, icon = Element.none
|
||||
, text = "Title"
|
||||
, content = Element.text <| "Hello World"
|
||||
}
|
||||
|>Widget.expansionPanel style.expansionPanel
|
||||
, Element.none
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
tab : Style Msg -> Model -> ( String, Element Msg, Element Msg )
|
||||
tab style model =
|
||||
( "Tab"
|
||||
, Widget.tab style.tab
|
||||
{ tabs =
|
||||
{ selected = model.tab
|
||||
, options =
|
||||
[ 1, 2, 3 ]
|
||||
|> List.map
|
||||
(\int ->
|
||||
{ text = "Tab " ++ (int |> String.fromInt)
|
||||
, icon = Element.none
|
||||
}
|
||||
)
|
||||
, onSelect = ChangedTab >> Just
|
||||
}
|
||||
, content =
|
||||
\selected ->
|
||||
(case selected of
|
||||
Just 0 ->
|
||||
"This is Tab 1"
|
||||
|
||||
Just 1 ->
|
||||
"This is the second tab"
|
||||
|
||||
Just 2 ->
|
||||
"The thrid and last tab"
|
||||
|
||||
_ ->
|
||||
"Please select a tab"
|
||||
)
|
||||
|> Element.text
|
||||
}
|
||||
, Element.none
|
||||
)
|
||||
|
||||
|
||||
modal : Style msg -> (Maybe Part -> msg) -> Model -> ( String, Element msg,Element msg )
|
||||
modal style changedSheet model =
|
||||
modal : Style msg -> (Maybe Part -> msg) -> Model -> ( String, Element msg, Element msg )
|
||||
modal style changedSheet _ =
|
||||
( "Modal"
|
||||
, [ Widget.button style.button
|
||||
{ onPress = Just <| changedSheet <| Just LeftSheet
|
||||
@ -252,12 +125,12 @@ modal style changedSheet model =
|
||||
}
|
||||
]
|
||||
|> Element.column Grid.simple
|
||||
,Element.none
|
||||
, Element.none
|
||||
)
|
||||
|
||||
|
||||
dialog : Style msg -> msg -> Model -> ( String, Element msg, Element msg )
|
||||
dialog style showDialog model =
|
||||
dialog style showDialog _ =
|
||||
( "Dialog"
|
||||
, Widget.button style.button
|
||||
{ onPress = Just showDialog
|
||||
@ -330,66 +203,6 @@ carousel style model =
|
||||
)
|
||||
|
||||
|
||||
iconButton : Style Msg -> Model -> ( String, Element Msg, Element Msg )
|
||||
iconButton style model =
|
||||
( "Icon Button"
|
||||
, [ Widget.button style.primaryButton
|
||||
{ text = "disable me"
|
||||
, icon = Icons.slash |> Element.html |> Element.el []
|
||||
, onPress =
|
||||
if model.button then
|
||||
Just <| ToggleButton False
|
||||
|
||||
else
|
||||
Nothing
|
||||
}
|
||||
, Widget.iconButton style.button
|
||||
{ text = "reset"
|
||||
, icon = Icons.repeat |> Element.html |> Element.el []
|
||||
, onPress = Just <| ToggleButton True
|
||||
}
|
||||
]
|
||||
|> Element.row Grid.simple
|
||||
, Element.column Grid.simple
|
||||
[ Element.row Grid.spacedEvenly
|
||||
[ "Button"
|
||||
|> Element.text
|
||||
, Widget.button style.button
|
||||
{ text = "reset"
|
||||
, icon = Icons.repeat |> Element.html |> Element.el []
|
||||
, onPress = Just <| ToggleButton True
|
||||
}
|
||||
]
|
||||
, Element.row Grid.spacedEvenly
|
||||
[ "Text button"
|
||||
|> Element.text
|
||||
, Widget.textButton style.button
|
||||
{ text = "reset"
|
||||
, onPress = Just <| ToggleButton True
|
||||
}
|
||||
]
|
||||
, Element.row Grid.spacedEvenly
|
||||
[ "Button"
|
||||
|> Element.text
|
||||
, Widget.iconButton style.button
|
||||
{ text = "reset"
|
||||
, icon = Icons.repeat |> Element.html |> Element.el []
|
||||
, onPress = Just <| ToggleButton True
|
||||
}
|
||||
]
|
||||
, Element.row Grid.spacedEvenly
|
||||
[ "Disabled button"
|
||||
|> Element.text
|
||||
, Widget.button style.button
|
||||
{ text = "reset"
|
||||
, icon = Icons.repeat |> Element.html |> Element.el []
|
||||
, onPress = Nothing
|
||||
}
|
||||
]
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
textInput : Style Msg -> Model -> ( String, Element Msg, Element Msg )
|
||||
textInput style model =
|
||||
( "Chip Text Input"
|
||||
@ -432,12 +245,108 @@ textInput style model =
|
||||
|> Element.wrappedRow [ Element.spacing 10 ]
|
||||
]
|
||||
|> Element.column Grid.simple
|
||||
, [ Element.row Grid.spacedEvenly
|
||||
[ "Nothing Selected"
|
||||
|> Element.text
|
||||
|> Element.el [ Element.width <| Element.fill ]
|
||||
, { chips = []
|
||||
, text = ""
|
||||
, placeholder = Nothing
|
||||
, label = "Label"
|
||||
, onChange = always Idle
|
||||
}
|
||||
|> Widget.textInput style.textInput
|
||||
]
|
||||
, Element.row Grid.spacedEvenly
|
||||
[ "Some chips"
|
||||
|> Element.text
|
||||
|> Element.el [ Element.width <| Element.fill ]
|
||||
, { chips =
|
||||
[ { icon = Icons.triangle |> Element.html |> Element.el []
|
||||
, text = "A"
|
||||
, onPress = Just Idle
|
||||
}
|
||||
, { icon = Icons.circle |> Element.html |> Element.el []
|
||||
, text = "B"
|
||||
, onPress = Just Idle
|
||||
}
|
||||
]
|
||||
, text = ""
|
||||
, placeholder = Nothing
|
||||
, label = "Label"
|
||||
, onChange = always Idle
|
||||
}
|
||||
|> Widget.textInput style.textInput
|
||||
]
|
||||
]
|
||||
|> Element.column Grid.simple
|
||||
)
|
||||
|
||||
|
||||
list : Style Msg -> Model -> ( String, Element Msg, Element Msg )
|
||||
list style _ =
|
||||
( "List"
|
||||
, [ Element.text <| "A"
|
||||
, Element.text <| "B"
|
||||
, Element.text <| "C"
|
||||
]
|
||||
|> Widget.column style.cardColumn
|
||||
, Element.none
|
||||
)
|
||||
|
||||
|
||||
sortTable : Style Msg -> Model -> ( String, Element Msg, Element Msg )
|
||||
sortTable _ model =
|
||||
( "Sort Table"
|
||||
, Widget.sortTable
|
||||
{ containerTable = Grid.simple
|
||||
, headerButton =
|
||||
{ container = []
|
||||
, labelRow = []
|
||||
, ifDisabled = []
|
||||
, ifActive = []
|
||||
}
|
||||
, ascIcon = Heroicons.cheveronUp [ Attributes.width 16 ] |> Element.html
|
||||
, descIcon = Heroicons.cheveronDown [ Attributes.width 16 ] |> Element.html
|
||||
, defaultIcon = Element.none
|
||||
}
|
||||
{ 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 }
|
||||
]
|
||||
, columns =
|
||||
[ Widget.intColumn
|
||||
{ title = "Id"
|
||||
, value = .id
|
||||
, toString = \int -> "#" ++ String.fromInt int
|
||||
, width = Element.fill
|
||||
}
|
||||
, Widget.stringColumn
|
||||
{ title = "Name"
|
||||
, value = .name
|
||||
, toString = identity
|
||||
, width = Element.fill
|
||||
}
|
||||
, Widget.floatColumn
|
||||
{ title = "rating"
|
||||
, value = .rating
|
||||
, toString = String.fromFloat
|
||||
, width = Element.fill
|
||||
}
|
||||
]
|
||||
, asc = model.table.asc
|
||||
, sortBy = model.table.title
|
||||
, onChange = ChangedSorting
|
||||
}
|
||||
, Element.none
|
||||
)
|
||||
|
||||
|
||||
view :
|
||||
Theme ->
|
||||
Theme
|
||||
->
|
||||
{ msgMapper : Msg -> msg
|
||||
, showDialog : msg
|
||||
, changedSheet : Maybe Part -> msg
|
||||
@ -450,9 +359,10 @@ view :
|
||||
}
|
||||
view theme { msgMapper, showDialog, changedSheet } model =
|
||||
let
|
||||
style = Theme.toStyle theme
|
||||
style =
|
||||
Theme.toStyle theme
|
||||
|
||||
map (a,b,c) =
|
||||
map ( a, b, c ) =
|
||||
( a
|
||||
, b |> Element.map msgMapper
|
||||
, c |> Element.map msgMapper
|
||||
@ -461,14 +371,17 @@ view theme { msgMapper, showDialog, changedSheet } model =
|
||||
{ title = "Stateless Views"
|
||||
, description = "Stateless views are simple functions that view some content. No wiring required."
|
||||
, items =
|
||||
[ iconButton style model |> map
|
||||
, select style model |> map
|
||||
, multiSelect style model |> map
|
||||
, expansionPanel style model |> map
|
||||
, modal style changedSheet model
|
||||
Example.toCardList
|
||||
{ idle = Idle |> msgMapper
|
||||
, msgMapper = ExampleSpecific >> msgMapper
|
||||
, style = style
|
||||
, model = model.example
|
||||
}
|
||||
++ [ modal style changedSheet model
|
||||
, carousel style model |> map
|
||||
, tab style model |> map
|
||||
, dialog style showDialog model
|
||||
, textInput style model |> map
|
||||
, list style model |> map
|
||||
, sortTable style model |> map
|
||||
]
|
||||
}
|
||||
|
390
example/src/View/Test.elm
Normal file
390
example/src/View/Test.elm
Normal file
@ -0,0 +1,390 @@
|
||||
module View.Test exposing (expansionPanel, iconButton, multiSelect, select, tab)
|
||||
|
||||
import Array
|
||||
import Data.Style exposing (Style)
|
||||
import Data.Theme as Theme exposing (Theme)
|
||||
import Element exposing (Element)
|
||||
import Element.Background as Background
|
||||
import Framework.Card as Card
|
||||
import Framework.Color as Color
|
||||
import Framework.Grid as Grid
|
||||
import Heroicons.Solid as Heroicons
|
||||
import Html.Attributes as Attributes
|
||||
import Icons
|
||||
import Layout exposing (Part(..))
|
||||
import Set exposing (Set)
|
||||
import Widget
|
||||
|
||||
|
||||
iconButton : msg -> Style msg -> List (Element msg)
|
||||
iconButton idle style =
|
||||
[ Element.row Grid.spacedEvenly
|
||||
[ "Button"
|
||||
|> Element.text
|
||||
, Widget.button style.button
|
||||
{ text = "Button"
|
||||
, icon = Icons.triangle |> Element.html |> Element.el []
|
||||
, onPress = Just idle
|
||||
}
|
||||
]
|
||||
, Element.row Grid.spacedEvenly
|
||||
[ "Text button"
|
||||
|> Element.text
|
||||
, Widget.textButton style.button
|
||||
{ text = "Button"
|
||||
, onPress = Just idle
|
||||
}
|
||||
]
|
||||
, Element.row Grid.spacedEvenly
|
||||
[ "Icon button"
|
||||
|> Element.text
|
||||
, Widget.iconButton style.button
|
||||
{ text = "Button"
|
||||
, icon = Icons.triangle |> Element.html |> Element.el []
|
||||
, onPress = Just idle
|
||||
}
|
||||
]
|
||||
, Element.row Grid.spacedEvenly
|
||||
[ "Disabled button"
|
||||
|> Element.text
|
||||
, Widget.button style.button
|
||||
{ text = "Button"
|
||||
, icon = Icons.triangle |> Element.html |> Element.el []
|
||||
, onPress = Nothing
|
||||
}
|
||||
]
|
||||
, Element.row Grid.spacedEvenly
|
||||
[ "Inactive Select button"
|
||||
|> Element.text
|
||||
, Widget.selectButton style.button
|
||||
( False
|
||||
, { text = "Button"
|
||||
, icon = Icons.triangle |> Element.html |> Element.el []
|
||||
, onPress = Just idle
|
||||
}
|
||||
)
|
||||
]
|
||||
, Element.row Grid.spacedEvenly
|
||||
[ "Active Select button"
|
||||
|> Element.text
|
||||
, Widget.selectButton style.button
|
||||
( True
|
||||
, { text = "Button"
|
||||
, icon = Icons.triangle |> Element.html |> Element.el []
|
||||
, onPress = Just idle
|
||||
}
|
||||
)
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
select : msg -> Style msg -> List (Element msg)
|
||||
select idle style =
|
||||
[ Element.row Grid.spacedEvenly
|
||||
[ "First selected"
|
||||
|> Element.text
|
||||
|> Element.el [ Element.width <| Element.fill ]
|
||||
, { selected = Just 0
|
||||
, options =
|
||||
[ 1, 2, 42 ]
|
||||
|> List.map
|
||||
(\int ->
|
||||
{ text = String.fromInt int
|
||||
, icon = Element.none
|
||||
}
|
||||
)
|
||||
, onSelect = always idle >> Just
|
||||
}
|
||||
|> Widget.select
|
||||
|> Widget.buttonRow
|
||||
{ list = style.row
|
||||
, button = style.button
|
||||
}
|
||||
]
|
||||
, Element.row Grid.spacedEvenly
|
||||
[ "Nothing selected"
|
||||
|> Element.text
|
||||
|> Element.el [ Element.width <| Element.fill ]
|
||||
, { selected = Nothing
|
||||
, options =
|
||||
[ 1, 2, 42 ]
|
||||
|> List.map
|
||||
(\int ->
|
||||
{ text = String.fromInt int
|
||||
, icon = Element.none
|
||||
}
|
||||
)
|
||||
, onSelect = always idle >> Just
|
||||
}
|
||||
|> Widget.select
|
||||
|> Widget.buttonRow
|
||||
{ list = style.row
|
||||
, button = style.button
|
||||
}
|
||||
]
|
||||
, Element.row Grid.spacedEvenly
|
||||
[ "Invalid selection"
|
||||
|> Element.text
|
||||
|> Element.el [ Element.width <| Element.fill ]
|
||||
, { selected = Just -1
|
||||
, options =
|
||||
[ 1, 2, 42 ]
|
||||
|> List.map
|
||||
(\int ->
|
||||
{ text = String.fromInt int
|
||||
, icon = Element.none
|
||||
}
|
||||
)
|
||||
, onSelect = always idle >> Just
|
||||
}
|
||||
|> Widget.select
|
||||
|> Widget.buttonRow
|
||||
{ list = style.row
|
||||
, button = style.button
|
||||
}
|
||||
]
|
||||
, Element.row Grid.spacedEvenly
|
||||
[ "Disabled selection"
|
||||
|> Element.text
|
||||
|> Element.el [ Element.width <| Element.fill ]
|
||||
, { selected = Just 0
|
||||
, options =
|
||||
[ 1, 2, 42 ]
|
||||
|> List.map
|
||||
(\int ->
|
||||
{ text = String.fromInt int
|
||||
, icon = Element.none
|
||||
}
|
||||
)
|
||||
, onSelect = always Nothing
|
||||
}
|
||||
|> Widget.select
|
||||
|> Widget.buttonRow
|
||||
{ list = style.row
|
||||
, button = style.button
|
||||
}
|
||||
]
|
||||
, Element.row Grid.spacedEvenly
|
||||
[ "Empty Options"
|
||||
|> Element.text
|
||||
|> Element.el [ Element.width <| Element.fill ]
|
||||
, { selected = Nothing
|
||||
, options =
|
||||
[]
|
||||
|> List.map
|
||||
(\int ->
|
||||
{ text = String.fromInt int
|
||||
, icon = Element.none
|
||||
}
|
||||
)
|
||||
, onSelect = always idle >> Just
|
||||
}
|
||||
|> Widget.select
|
||||
|> Widget.buttonRow
|
||||
{ list = style.row
|
||||
, button = style.button
|
||||
}
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
multiSelect : msg -> Style msg -> List (Element msg)
|
||||
multiSelect idle style =
|
||||
[ Element.row Grid.spacedEvenly
|
||||
[ "Some selected"
|
||||
|> Element.text
|
||||
|> Element.el [ Element.width <| Element.fill ]
|
||||
, { selected = Set.fromList [ 0, 1 ]
|
||||
, options =
|
||||
[ 1, 2, 42 ]
|
||||
|> List.map
|
||||
(\int ->
|
||||
{ text = String.fromInt int
|
||||
, icon = Element.none
|
||||
}
|
||||
)
|
||||
, onSelect = always idle >> Just
|
||||
}
|
||||
|> Widget.multiSelect
|
||||
|> Widget.buttonRow
|
||||
{ list = style.row
|
||||
, button = style.button
|
||||
}
|
||||
]
|
||||
, Element.row Grid.spacedEvenly
|
||||
[ "Nothing selected"
|
||||
|> Element.text
|
||||
|> Element.el [ Element.width <| Element.fill ]
|
||||
, { selected = Set.empty
|
||||
, options =
|
||||
[ 1, 2, 42 ]
|
||||
|> List.map
|
||||
(\int ->
|
||||
{ text = String.fromInt int
|
||||
, icon = Element.none
|
||||
}
|
||||
)
|
||||
, onSelect = always idle >> Just
|
||||
}
|
||||
|> Widget.multiSelect
|
||||
|> Widget.buttonRow
|
||||
{ list = style.row
|
||||
, button = style.button
|
||||
}
|
||||
]
|
||||
, Element.row Grid.spacedEvenly
|
||||
[ "Invalid selection"
|
||||
|> Element.text
|
||||
|> Element.el [ Element.width <| Element.fill ]
|
||||
, { selected = Set.singleton -1
|
||||
, options =
|
||||
[ 1, 2, 42 ]
|
||||
|> List.map
|
||||
(\int ->
|
||||
{ text = String.fromInt int
|
||||
, icon = Element.none
|
||||
}
|
||||
)
|
||||
, onSelect = always idle >> Just
|
||||
}
|
||||
|> Widget.multiSelect
|
||||
|> Widget.buttonRow
|
||||
{ list = style.row
|
||||
, button = style.button
|
||||
}
|
||||
]
|
||||
, Element.row Grid.spacedEvenly
|
||||
[ "Disabled selection"
|
||||
|> Element.text
|
||||
|> Element.el [ Element.width <| Element.fill ]
|
||||
, { selected = Set.singleton 0
|
||||
, options =
|
||||
[ 1, 2, 42 ]
|
||||
|> List.map
|
||||
(\int ->
|
||||
{ text = String.fromInt int
|
||||
, icon = Element.none
|
||||
}
|
||||
)
|
||||
, onSelect = always Nothing
|
||||
}
|
||||
|> Widget.multiSelect
|
||||
|> Widget.buttonRow
|
||||
{ list = style.row
|
||||
, button = style.button
|
||||
}
|
||||
]
|
||||
, Element.row Grid.spacedEvenly
|
||||
[ "Empty Options"
|
||||
|> Element.text
|
||||
|> Element.el [ Element.width <| Element.fill ]
|
||||
, { selected = Set.empty
|
||||
, options =
|
||||
[]
|
||||
|> List.map
|
||||
(\int ->
|
||||
{ text = String.fromInt int
|
||||
, icon = Element.none
|
||||
}
|
||||
)
|
||||
, onSelect = always idle >> Just
|
||||
}
|
||||
|> Widget.multiSelect
|
||||
|> Widget.buttonRow
|
||||
{ list = style.row
|
||||
, button = style.button
|
||||
}
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
expansionPanel : msg -> Style msg -> List (Element msg)
|
||||
expansionPanel idle style =
|
||||
[ Element.row Grid.spacedEvenly
|
||||
[ "Collapsed"
|
||||
|> Element.text
|
||||
|> Element.el [ Element.width <| Element.fill ]
|
||||
, { onToggle = always idle
|
||||
, isExpanded = False
|
||||
, icon = Icons.triangle |> Element.html |> Element.el []
|
||||
, text = "Button"
|
||||
, content = Element.text <| "Hidden Message"
|
||||
}
|
||||
|> Widget.expansionPanel style.expansionPanel
|
||||
]
|
||||
, Element.row Grid.spacedEvenly
|
||||
[ "Expanded"
|
||||
|> Element.text
|
||||
|> Element.el [ Element.width <| Element.fill ]
|
||||
, { onToggle = always idle
|
||||
, isExpanded = True
|
||||
, icon = Icons.triangle |> Element.html |> Element.el []
|
||||
, text = "Button"
|
||||
, content = Element.text <| "Hidden Message"
|
||||
}
|
||||
|> Widget.expansionPanel style.expansionPanel
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
tab : msg -> Style msg -> List (Element msg)
|
||||
tab idle style =
|
||||
[ Element.row Grid.spacedEvenly
|
||||
[ "Nothing selected"
|
||||
|> Element.text
|
||||
|> Element.el [ Element.width <| Element.fill ]
|
||||
, Widget.tab style.tab
|
||||
{ tabs =
|
||||
{ selected = Nothing
|
||||
, options =
|
||||
[ 1, 2, 3 ]
|
||||
|> List.map
|
||||
(\int ->
|
||||
{ text = int |> String.fromInt
|
||||
, icon = Element.none
|
||||
}
|
||||
)
|
||||
, onSelect = always idle >> Just
|
||||
}
|
||||
, content =
|
||||
\selected ->
|
||||
(case selected of
|
||||
Nothing ->
|
||||
"Please select a tab"
|
||||
|
||||
_ ->
|
||||
""
|
||||
)
|
||||
|> Element.text
|
||||
}
|
||||
]
|
||||
, Element.row Grid.spacedEvenly
|
||||
[ "Tab selected"
|
||||
|> Element.text
|
||||
|> Element.el [ Element.width <| Element.fill ]
|
||||
, Widget.tab style.tab
|
||||
{ tabs =
|
||||
{ selected = Just 0
|
||||
, options =
|
||||
[ 1, 2, 3 ]
|
||||
|> List.map
|
||||
(\int ->
|
||||
{ text = int |> String.fromInt
|
||||
, icon = Element.none
|
||||
}
|
||||
)
|
||||
, onSelect = always idle >> Just
|
||||
}
|
||||
, content =
|
||||
\selected ->
|
||||
(case selected of
|
||||
Just 0 ->
|
||||
"First Tab selected"
|
||||
|
||||
_ ->
|
||||
"Please select a tab"
|
||||
)
|
||||
|> Element.text
|
||||
}
|
||||
]
|
||||
]
|
181
src/Internal/SortTable.elm
Normal file
181
src/Internal/SortTable.elm
Normal file
@ -0,0 +1,181 @@
|
||||
module Internal.SortTable exposing
|
||||
( Column
|
||||
, ColumnType
|
||||
, SortTable
|
||||
, floatColumn
|
||||
, intColumn
|
||||
, sortTable
|
||||
, stringColumn
|
||||
, unsortableColumn
|
||||
)
|
||||
|
||||
import Element exposing (Element, Length)
|
||||
import Internal.Button as Button
|
||||
import Widget.Style exposing (SortTableStyle)
|
||||
|
||||
|
||||
{-| A Sortable list allows you to sort coulmn.
|
||||
-}
|
||||
type ColumnType a
|
||||
= StringColumn { value : a -> String, toString : String -> String }
|
||||
| IntColumn { value : a -> Int, toString : Int -> String }
|
||||
| FloatColumn { value : a -> Float, toString : Float -> String }
|
||||
| UnsortableColumn (a -> String)
|
||||
|
||||
|
||||
{-| The Model contains the sorting column name and if ascending or descending.
|
||||
-}
|
||||
type alias SortTable a msg =
|
||||
{ content : List a
|
||||
, columns : List (Column a)
|
||||
, sortBy : String
|
||||
, asc : Bool
|
||||
, onChange : String -> msg
|
||||
}
|
||||
|
||||
|
||||
type Column a
|
||||
= Column
|
||||
{ title : String
|
||||
, content : ColumnType a
|
||||
, width : Length
|
||||
}
|
||||
|
||||
|
||||
unsortableColumn : { title : String, toString : a -> String, width : Length } -> Column a
|
||||
unsortableColumn { title, toString, width } =
|
||||
Column
|
||||
{ title = title
|
||||
, content = UnsortableColumn toString
|
||||
, width = width
|
||||
}
|
||||
|
||||
|
||||
{-| A Column containing a Int
|
||||
-}
|
||||
intColumn : { title : String, value : a -> Int, toString : Int -> String, width : Length } -> Column a
|
||||
intColumn { title, value, toString, width } =
|
||||
Column
|
||||
{ title = title
|
||||
, content = IntColumn { value = value, toString = toString }
|
||||
, width = width
|
||||
}
|
||||
|
||||
|
||||
{-| A Column containing a Float
|
||||
-}
|
||||
floatColumn : { title : String, value : a -> Float, toString : Float -> String, width : Length } -> Column a
|
||||
floatColumn { title, value, toString, width } =
|
||||
Column
|
||||
{ title = title
|
||||
, content = FloatColumn { value = value, toString = toString }
|
||||
, width = width
|
||||
}
|
||||
|
||||
|
||||
{-| A Column containing a String
|
||||
-}
|
||||
stringColumn : { title : String, value : a -> String, toString : String -> String, width : Length } -> Column a
|
||||
stringColumn { title, value, toString, width } =
|
||||
Column
|
||||
{ title = title
|
||||
, content = StringColumn { value = value, toString = toString }
|
||||
, width = width
|
||||
}
|
||||
|
||||
|
||||
{-| The View
|
||||
-}
|
||||
sortTable :
|
||||
SortTableStyle msg
|
||||
-> SortTable a msg
|
||||
-> Element msg
|
||||
sortTable style model =
|
||||
let
|
||||
findTitle : List (Column a) -> Maybe (ColumnType a)
|
||||
findTitle list =
|
||||
case list of
|
||||
[] ->
|
||||
Nothing
|
||||
|
||||
(Column head) :: tail ->
|
||||
if head.title == model.sortBy then
|
||||
Just head.content
|
||||
|
||||
else
|
||||
findTitle tail
|
||||
in
|
||||
Element.table style.containerTable
|
||||
{ data =
|
||||
model.content
|
||||
|> (model.columns
|
||||
|> findTitle
|
||||
|> Maybe.andThen
|
||||
(\c ->
|
||||
case c of
|
||||
StringColumn { value } ->
|
||||
Just <| List.sortBy value
|
||||
|
||||
IntColumn { value } ->
|
||||
Just <| List.sortBy value
|
||||
|
||||
FloatColumn { value } ->
|
||||
Just <| List.sortBy value
|
||||
|
||||
UnsortableColumn _ ->
|
||||
Nothing
|
||||
)
|
||||
|> Maybe.withDefault identity
|
||||
)
|
||||
|> (if model.asc then
|
||||
identity
|
||||
|
||||
else
|
||||
List.reverse
|
||||
)
|
||||
, columns =
|
||||
model.columns
|
||||
|> List.map
|
||||
(\(Column column) ->
|
||||
{ header =
|
||||
Button.button style.headerButton
|
||||
{ text = column.title
|
||||
, icon =
|
||||
if column.title == model.sortBy then
|
||||
if model.asc then
|
||||
style.ascIcon
|
||||
|
||||
else
|
||||
style.descIcon
|
||||
|
||||
else
|
||||
style.defaultIcon
|
||||
, onPress =
|
||||
case column.content of
|
||||
UnsortableColumn _ ->
|
||||
Nothing
|
||||
|
||||
_ ->
|
||||
Just <| model.onChange <| column.title
|
||||
}
|
||||
, width = column.width
|
||||
, view =
|
||||
(case column.content of
|
||||
IntColumn { value, toString } ->
|
||||
value >> toString
|
||||
|
||||
FloatColumn { value, toString } ->
|
||||
value >> toString
|
||||
|
||||
StringColumn { value, toString } ->
|
||||
value >> toString
|
||||
|
||||
UnsortableColumn toString ->
|
||||
toString
|
||||
)
|
||||
>> Element.text
|
||||
>> List.singleton
|
||||
>> Element.paragraph []
|
||||
}
|
||||
)
|
||||
}
|
100
src/Widget.elm
100
src/Widget.elm
@ -3,8 +3,10 @@ module Widget exposing
|
||||
, Select, MultiSelect, selectButton, select, multiSelect
|
||||
, Dialog, modal, dialog
|
||||
, ExpansionPanel, expansionPanel
|
||||
, row, column, buttonRow, buttonColumn
|
||||
, ColumnType, sortTable, floatColumn, intColumn, stringColumn, unsortableColumn
|
||||
, TextInputStyle, textInput, carousel, tab
|
||||
, Tab, buttonColumn, buttonRow, column, row
|
||||
, Tab
|
||||
)
|
||||
|
||||
{-| This module contains functions for displaying data.
|
||||
@ -30,6 +32,16 @@ module Widget exposing
|
||||
@docs ExpansionPanel, expansionPanel
|
||||
|
||||
|
||||
# List
|
||||
|
||||
@docs row, column, buttonRow, buttonColumn
|
||||
|
||||
|
||||
# SortTable
|
||||
|
||||
@docs ColumnType, sortTable, floatColumn, intColumn, stringColumn, unsortableColumn
|
||||
|
||||
|
||||
# Other Widgets
|
||||
|
||||
@docs TextInputStyle, textInput, carousel, tab
|
||||
@ -37,16 +49,17 @@ module Widget exposing
|
||||
-}
|
||||
|
||||
import Array exposing (Array)
|
||||
import Element exposing (Attribute, Element)
|
||||
import Element exposing (Attribute, Element, Length)
|
||||
import Element.Input exposing (Placeholder)
|
||||
import Internal.Button as Button
|
||||
import Internal.Dialog as Dialog
|
||||
import Internal.ExpansionPanel as ExpansionPanel
|
||||
import Internal.List as List
|
||||
import Internal.Select as Select
|
||||
import Internal.SortTable as SortTable
|
||||
import Internal.TextInput as TextInput
|
||||
import Set exposing (Set)
|
||||
import Widget.Style exposing (ButtonStyle, ColumnStyle, DialogStyle, ExpansionPanelStyle, RowStyle, TabStyle)
|
||||
import Widget.Style exposing (ButtonStyle, ColumnStyle, DialogStyle, ExpansionPanelStyle, RowStyle, SortTableStyle, TabStyle)
|
||||
|
||||
|
||||
|
||||
@ -322,6 +335,87 @@ buttonColumn =
|
||||
|
||||
|
||||
|
||||
{----------------------------------------------------------
|
||||
- SORT TABLE
|
||||
----------------------------------------------------------}
|
||||
|
||||
|
||||
{-| A Sortable list allows you to sort coulmn.
|
||||
-}
|
||||
type alias ColumnType a =
|
||||
SortTable.ColumnType a
|
||||
|
||||
|
||||
type alias Column a =
|
||||
SortTable.Column a
|
||||
|
||||
|
||||
unsortableColumn :
|
||||
{ title : String
|
||||
, toString : a -> String
|
||||
, width : Length
|
||||
}
|
||||
-> Column a
|
||||
unsortableColumn =
|
||||
SortTable.unsortableColumn
|
||||
|
||||
|
||||
{-| A Column containing a Int
|
||||
-}
|
||||
intColumn :
|
||||
{ title : String
|
||||
, value : a -> Int
|
||||
, toString : Int -> String
|
||||
, width : Length
|
||||
}
|
||||
-> Column a
|
||||
intColumn =
|
||||
SortTable.intColumn
|
||||
|
||||
|
||||
{-| A Column containing a Float
|
||||
-}
|
||||
floatColumn :
|
||||
{ title : String
|
||||
, value : a -> Float
|
||||
, toString : Float -> String
|
||||
, width : Length
|
||||
}
|
||||
-> Column a
|
||||
floatColumn =
|
||||
SortTable.floatColumn
|
||||
|
||||
|
||||
{-| A Column containing a String
|
||||
-}
|
||||
stringColumn :
|
||||
{ title : String
|
||||
, value : a -> String
|
||||
, toString : String -> String
|
||||
, width : Length
|
||||
}
|
||||
-> Column a
|
||||
stringColumn =
|
||||
SortTable.stringColumn
|
||||
|
||||
|
||||
{-| The View
|
||||
-}
|
||||
sortTable :
|
||||
SortTableStyle msg
|
||||
->
|
||||
{ content : List a
|
||||
, columns : List (Column a)
|
||||
, sortBy : String
|
||||
, asc : Bool
|
||||
, onChange : String -> msg
|
||||
}
|
||||
-> Element msg
|
||||
sortTable =
|
||||
SortTable.sortTable
|
||||
|
||||
|
||||
|
||||
{----------------------------------------------------------
|
||||
- OTHER STATELESS WIDGETS
|
||||
----------------------------------------------------------}
|
||||
|
@ -1,215 +0,0 @@
|
||||
module Widget.SortTable exposing
|
||||
( Model, init, view, sortBy
|
||||
, intColumn, floatColumn, stringColumn
|
||||
)
|
||||
|
||||
{-| A Sortable list allows you to sort coulmn.
|
||||
|
||||
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 }
|
||||
]
|
||||
, columns =
|
||||
[ SortTable.intColumn
|
||||
{ title = "Id"
|
||||
, value = .id
|
||||
, toString = \int -> "#" ++ String.fromInt int
|
||||
}
|
||||
, SortTable.stringColumn
|
||||
{ title = "Name"
|
||||
, value = .name
|
||||
, toString = identity
|
||||
}
|
||||
, SortTable.floatColumn
|
||||
{ title = "rating"
|
||||
, value = .rating
|
||||
, toString = String.fromFloat
|
||||
}
|
||||
]
|
||||
, 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.text <|
|
||||
if model.asc then
|
||||
"/\"
|
||||
else
|
||||
"\/"
|
||||
]
|
||||
|> Element.row [Font.bold]
|
||||
else
|
||||
config.header |> Element.text
|
||||
}
|
||||
, view = config.view >> Element.text
|
||||
, width = Element.fill
|
||||
}
|
||||
)
|
||||
})
|
||||
|> Element.table []
|
||||
|
||||
|
||||
# Basics
|
||||
|
||||
@docs Model, init, view, sortBy
|
||||
|
||||
|
||||
# Columns
|
||||
|
||||
@docs intColumn, floatColumn, stringColumn
|
||||
|
||||
-}
|
||||
|
||||
|
||||
type ColumnType a
|
||||
= StringColumn { value : a -> String, toString : String -> String }
|
||||
| IntColumn { value : a -> Int, toString : Int -> String }
|
||||
| FloatColumn { value : a -> Float, toString : Float -> String }
|
||||
|
||||
|
||||
{-| The Model contains the sorting column name and if ascending or descending.
|
||||
-}
|
||||
type alias Model =
|
||||
{ title : String
|
||||
, asc : Bool
|
||||
}
|
||||
|
||||
|
||||
type alias Column a =
|
||||
{ title : String
|
||||
, content : ColumnType a
|
||||
}
|
||||
|
||||
|
||||
{-| The initial State setting the sorting column name to the empty string.
|
||||
-}
|
||||
init : Model
|
||||
init =
|
||||
{ title = "", asc = True }
|
||||
|
||||
|
||||
{-| A Column containing a Int
|
||||
-}
|
||||
intColumn : { title : String, value : a -> Int, toString : Int -> String } -> Column a
|
||||
intColumn { title, value, toString } =
|
||||
{ title = title
|
||||
, content = IntColumn { value = value, toString = toString }
|
||||
}
|
||||
|
||||
|
||||
{-| A Column containing a Float
|
||||
-}
|
||||
floatColumn : { title : String, value : a -> Float, toString : Float -> String } -> Column a
|
||||
floatColumn { title, value, toString } =
|
||||
{ title = title
|
||||
, content = FloatColumn { value = value, toString = toString }
|
||||
}
|
||||
|
||||
|
||||
{-| A Column containing a String
|
||||
-}
|
||||
stringColumn : { title : String, value : a -> String, toString : String -> String } -> Column a
|
||||
stringColumn { title, value, toString } =
|
||||
{ title = title
|
||||
, content = StringColumn { value = value, toString = toString }
|
||||
}
|
||||
|
||||
|
||||
{-| Change the sorting criteras.
|
||||
|
||||
sortBy =
|
||||
identity
|
||||
|
||||
-}
|
||||
sortBy : { title : String, asc : Bool } -> Model
|
||||
sortBy =
|
||||
identity
|
||||
|
||||
|
||||
{-| The View
|
||||
-}
|
||||
view :
|
||||
{ content : List a
|
||||
, columns : List (Column a)
|
||||
, model : Model
|
||||
}
|
||||
->
|
||||
{ data : List a
|
||||
, columns : List { header : String, view : a -> String }
|
||||
}
|
||||
view { content, columns, model } =
|
||||
let
|
||||
findTitle : List (Column a) -> Maybe (ColumnType a)
|
||||
findTitle list =
|
||||
case list of
|
||||
[] ->
|
||||
Nothing
|
||||
|
||||
head :: tail ->
|
||||
if head.title == model.title then
|
||||
Just head.content
|
||||
|
||||
else
|
||||
findTitle tail
|
||||
in
|
||||
{ data =
|
||||
content
|
||||
|> (columns
|
||||
|> findTitle
|
||||
|> Maybe.map
|
||||
(\c ->
|
||||
case c of
|
||||
StringColumn { value } ->
|
||||
List.sortBy value
|
||||
|
||||
IntColumn { value } ->
|
||||
List.sortBy value
|
||||
|
||||
FloatColumn { value } ->
|
||||
List.sortBy value
|
||||
)
|
||||
|> Maybe.withDefault identity
|
||||
)
|
||||
|> (if model.asc then
|
||||
identity
|
||||
|
||||
else
|
||||
List.reverse
|
||||
)
|
||||
, columns =
|
||||
columns
|
||||
|> List.map
|
||||
(\column ->
|
||||
{ header = column.title
|
||||
, view =
|
||||
case column.content of
|
||||
IntColumn { value, toString } ->
|
||||
value >> toString
|
||||
|
||||
FloatColumn { value, toString } ->
|
||||
value >> toString
|
||||
|
||||
StringColumn { value, toString } ->
|
||||
value >> toString
|
||||
}
|
||||
)
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
module Widget.Style exposing (ButtonStyle, ColumnStyle, DialogStyle, ExpansionPanelStyle, RowStyle, SnackbarStyle, Style, TabStyle, TextInputStyle)
|
||||
module Widget.Style exposing (ButtonStyle, ColumnStyle, DialogStyle, ExpansionPanelStyle, RowStyle, SnackbarStyle, SortTableStyle, Style, TabStyle, TextInputStyle)
|
||||
|
||||
import Element exposing (Attribute, Element)
|
||||
import Html exposing (Html)
|
||||
@ -72,6 +72,15 @@ type alias ColumnStyle msg =
|
||||
}
|
||||
|
||||
|
||||
type alias SortTableStyle msg =
|
||||
{ containerTable : List (Attribute msg)
|
||||
, headerButton : ButtonStyle msg
|
||||
, ascIcon : Element Never
|
||||
, descIcon : Element Never
|
||||
, defaultIcon : Element Never
|
||||
}
|
||||
|
||||
|
||||
type alias Style style msg =
|
||||
{ style
|
||||
| snackbar : SnackbarStyle msg
|
||||
|
Loading…
Reference in New Issue
Block a user