mirror of
https://github.com/Orasund/elm-ui-widgets.git
synced 2024-11-22 22:33:33 +03:00
starting work on List-Widget
This commit is contained in:
parent
8bb1d17371
commit
732a18720d
@ -1,233 +0,0 @@
|
|||||||
module Component exposing (Model, Msg(..), init, update, view)
|
|
||||||
|
|
||||||
import Browser
|
|
||||||
import Element exposing (Color, Element)
|
|
||||||
import Element.Background as Background
|
|
||||||
import Element.Input as Input
|
|
||||||
import Element.Border as Border
|
|
||||||
import Element.Font as Font
|
|
||||||
import Framework
|
|
||||||
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 Set exposing (Set)
|
|
||||||
import Time
|
|
||||||
import Widget
|
|
||||||
import Widget.Style exposing (ButtonStyle)
|
|
||||||
import Widget.FilterSelect as FilterSelect
|
|
||||||
import Widget.FilterMultiSelect as FilterMultiSelect
|
|
||||||
import Widget.ScrollingNav as ScrollingNav
|
|
||||||
import Widget.Snackbar as Snackbar
|
|
||||||
import Widget.ValidatedInput as ValidatedInput
|
|
||||||
import Data.Style exposing (style)
|
|
||||||
|
|
||||||
type alias Model =
|
|
||||||
{ filterSelect : FilterSelect.Model
|
|
||||||
, filterMultiSelect : FilterMultiSelect.Model
|
|
||||||
, validatedInput : ValidatedInput.Model () ( String, String )
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
type Msg
|
|
||||||
= FilterSelectSpecific FilterSelect.Msg
|
|
||||||
| FilterMultiSelectSpecific FilterMultiSelect.Msg
|
|
||||||
| ValidatedInputSpecific ValidatedInput.Msg
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
init : Model
|
|
||||||
init =
|
|
||||||
{ filterSelect =
|
|
||||||
[ "Apple"
|
|
||||||
, "Kiwi"
|
|
||||||
, "Strawberry"
|
|
||||||
, "Pineapple"
|
|
||||||
, "Mango"
|
|
||||||
, "Grapes"
|
|
||||||
, "Watermelon"
|
|
||||||
, "Orange"
|
|
||||||
, "Lemon"
|
|
||||||
, "Blueberry"
|
|
||||||
, "Grapefruit"
|
|
||||||
, "Coconut"
|
|
||||||
, "Cherry"
|
|
||||||
, "Banana"
|
|
||||||
]
|
|
||||||
|> Set.fromList
|
|
||||||
|> FilterSelect.init
|
|
||||||
, filterMultiSelect =
|
|
||||||
[ "Apple"
|
|
||||||
, "Kiwi"
|
|
||||||
, "Strawberry"
|
|
||||||
, "Pineapple"
|
|
||||||
, "Mango"
|
|
||||||
, "Grapes"
|
|
||||||
, "Watermelon"
|
|
||||||
, "Orange"
|
|
||||||
, "Lemon"
|
|
||||||
, "Blueberry"
|
|
||||||
, "Grapefruit"
|
|
||||||
, "Coconut"
|
|
||||||
, "Cherry"
|
|
||||||
, "Banana"
|
|
||||||
]
|
|
||||||
|> Set.fromList
|
|
||||||
|> FilterMultiSelect.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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
update : Msg -> Model -> ( Model, Cmd Msg )
|
|
||||||
update msg model =
|
|
||||||
case msg of
|
|
||||||
FilterSelectSpecific m ->
|
|
||||||
( { model
|
|
||||||
| filterSelect = model.filterSelect |> FilterSelect.update m
|
|
||||||
}
|
|
||||||
, Cmd.none
|
|
||||||
)
|
|
||||||
|
|
||||||
FilterMultiSelectSpecific m ->
|
|
||||||
( { model
|
|
||||||
| filterMultiSelect = model.filterMultiSelect |> FilterMultiSelect.update m
|
|
||||||
}
|
|
||||||
, Cmd.none
|
|
||||||
)
|
|
||||||
|
|
||||||
ValidatedInputSpecific m ->
|
|
||||||
( { model
|
|
||||||
| validatedInput = model.validatedInput |> ValidatedInput.update m
|
|
||||||
}
|
|
||||||
, Cmd.none
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
filterSelect : FilterSelect.Model -> (String,Element Msg)
|
|
||||||
filterSelect model =
|
|
||||||
( "Filter Select"
|
|
||||||
, case model.selected of
|
|
||||||
Just selected ->
|
|
||||||
Element.row Grid.compact
|
|
||||||
[ 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 ]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
Nothing ->
|
|
||||||
Element.column Grid.simple
|
|
||||||
[ FilterSelect.viewInput Input.simple
|
|
||||||
model
|
|
||||||
{ msgMapper = FilterSelectSpecific
|
|
||||||
, placeholder =
|
|
||||||
Just <|
|
|
||||||
Input.placeholder [] <|
|
|
||||||
Element.text <|
|
|
||||||
"Fruit"
|
|
||||||
, label = "Fruit"
|
|
||||||
}
|
|
||||||
, model
|
|
||||||
|> FilterSelect.viewOptions
|
|
||||||
|> List.map
|
|
||||||
(\string ->
|
|
||||||
Input.button (Button.simple ++ Tag.simple)
|
|
||||||
{ onPress = Just <| FilterSelectSpecific <| FilterSelect.Selected <| Just <| string
|
|
||||||
, label = Element.text string
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|> Element.wrappedRow [ Element.spacing 10 ]
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
filterMultiSelect : FilterMultiSelect.Model -> (String,Element Msg)
|
|
||||||
filterMultiSelect model =
|
|
||||||
( "Filter Multi Select"
|
|
||||||
, [ FilterMultiSelect.viewInput model
|
|
||||||
{ msgMapper = FilterMultiSelectSpecific
|
|
||||||
, placeholder =
|
|
||||||
Just <|
|
|
||||||
Input.placeholder [] <|
|
|
||||||
Element.text <|
|
|
||||||
"Fruit"
|
|
||||||
, label = "Fruit"
|
|
||||||
, toChip = \string ->
|
|
||||||
{ text = string
|
|
||||||
, onPress = Just <| FilterMultiSelectSpecific <| FilterMultiSelect.ToggleSelected <| string
|
|
||||||
, icon = Element.none
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|> Widget.textInput style.textInput
|
|
||||||
|
|
||||||
, model
|
|
||||||
|> FilterMultiSelect.viewOptions
|
|
||||||
|> List.map
|
|
||||||
(\string ->
|
|
||||||
Input.button (Button.simple ++ Tag.simple)
|
|
||||||
{ onPress = Just <| FilterMultiSelectSpecific <| FilterMultiSelect.ToggleSelected <| string
|
|
||||||
, label = Element.text string
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|> Element.wrappedRow [ Element.spacing 10 ]
|
|
||||||
]
|
|
||||||
|> Element.column Grid.simple
|
|
||||||
)
|
|
||||||
|
|
||||||
validatedInput : ValidatedInput.Model () ( String, String ) -> (String,Element Msg)
|
|
||||||
validatedInput model =
|
|
||||||
( "Validated Input"
|
|
||||||
, ValidatedInput.view Input.simple
|
|
||||||
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)
|
|
||||||
]
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
view : (Msg -> msg) -> Model ->
|
|
||||||
{ title : String
|
|
||||||
, description : String
|
|
||||||
, items : List (String,Element msg)
|
|
||||||
}
|
|
||||||
view msgMapper model =
|
|
||||||
{ title = "Components"
|
|
||||||
, description = "Components have a Model, an Update- and sometimes even a Subscription-function. It takes some time to set them up correctly."
|
|
||||||
, items =
|
|
||||||
[ filterSelect model.filterSelect
|
|
||||||
, filterMultiSelect model.filterMultiSelect
|
|
||||||
, validatedInput model.validatedInput
|
|
||||||
]
|
|
||||||
|> List.map (Tuple.mapSecond (Element.map msgMapper) )
|
|
||||||
}
|
|
@ -1,19 +1,19 @@
|
|||||||
module Data.Section exposing (Section(..),asList,toString,fromString)
|
module Data.Section exposing (Section(..), asList, fromString, toString)
|
||||||
|
|
||||||
|
|
||||||
type Section
|
type Section
|
||||||
= ComponentViews
|
= ReusableViews
|
||||||
| ReusableViews
|
|
||||||
| StatelessViews
|
| StatelessViews
|
||||||
|
|
||||||
|
|
||||||
asList : List Section
|
asList : List Section
|
||||||
asList =
|
asList =
|
||||||
[ StatelessViews, ReusableViews, ComponentViews ]
|
[ StatelessViews, ReusableViews ]
|
||||||
|
|
||||||
|
|
||||||
toString : Section -> String
|
toString : Section -> String
|
||||||
toString section =
|
toString section =
|
||||||
case section of
|
case section of
|
||||||
ComponentViews ->
|
|
||||||
"Component"
|
|
||||||
|
|
||||||
ReusableViews ->
|
ReusableViews ->
|
||||||
"Reusable"
|
"Reusable"
|
||||||
@ -21,11 +21,10 @@ toString section =
|
|||||||
StatelessViews ->
|
StatelessViews ->
|
||||||
"Stateless"
|
"Stateless"
|
||||||
|
|
||||||
|
|
||||||
fromString : String -> Maybe Section
|
fromString : String -> Maybe Section
|
||||||
fromString string =
|
fromString string =
|
||||||
case string of
|
case string of
|
||||||
"Component" ->
|
|
||||||
Just ComponentViews
|
|
||||||
|
|
||||||
"Reusable" ->
|
"Reusable" ->
|
||||||
Just ReusableViews
|
Just ReusableViews
|
||||||
|
@ -1,223 +1,20 @@
|
|||||||
module Data.Style exposing (style)
|
module Data.Style exposing (Style)
|
||||||
|
|
||||||
import Widget exposing (TextInputStyle)
|
|
||||||
import Widget.Style exposing (Style,ButtonStyle)
|
|
||||||
import Element exposing (Attribute)
|
import Element exposing (Attribute)
|
||||||
import Element.Input as Input
|
import Widget.Style exposing (ButtonStyle, DialogStyle, ExpansionPanelStyle,
|
||||||
import Element.Font as Font
|
SnackbarStyle ,RowStyle,ColumnStyle,TextInputStyle,TabStyle)
|
||||||
import Element.Border as Border
|
|
||||||
import Framework
|
|
||||||
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 Icons
|
|
||||||
|
|
||||||
textButton : ButtonStyle msg
|
type alias Style msg =
|
||||||
textButton =
|
Widget.Style.Style
|
||||||
{ container = Button.simple
|
{ dialog : DialogStyle msg
|
||||||
, label = Grid.simple
|
, expansionPanel : ExpansionPanelStyle msg
|
||||||
, disabled = Color.disabled
|
|
||||||
, active = Color.primary
|
|
||||||
}
|
|
||||||
|
|
||||||
simpleButton : ButtonStyle msg
|
|
||||||
simpleButton =
|
|
||||||
{ container = Button.simple ++ Color.primary
|
|
||||||
, label = Grid.simple
|
|
||||||
, disabled = Color.disabled
|
|
||||||
, active = Color.primary
|
|
||||||
}
|
|
||||||
|
|
||||||
buttonStyle : ButtonStyle msg
|
|
||||||
buttonStyle =
|
|
||||||
{ label = [ Element.spacing 8]
|
|
||||||
, container = Button.simple
|
|
||||||
, disabled = Color.disabled
|
|
||||||
, active = Color.primary
|
|
||||||
}
|
|
||||||
|
|
||||||
tabButtonStyle :ButtonStyle msg
|
|
||||||
tabButtonStyle=
|
|
||||||
{ label = [ Element.spacing 8]
|
|
||||||
, container = Button.simple ++ Group.top
|
|
||||||
, disabled = Color.disabled
|
|
||||||
, active = Color.primary
|
|
||||||
}
|
|
||||||
|
|
||||||
textInputStyle =
|
|
||||||
{ chip = chipButtonStyle
|
|
||||||
, chipsRow =
|
|
||||||
[ Element.width <| Element.shrink
|
|
||||||
, Element.spacing <| 4
|
|
||||||
, Element.paddingEach
|
|
||||||
{ top = 8
|
|
||||||
, left = 0
|
|
||||||
, right = 0
|
|
||||||
, bottom = 8
|
|
||||||
}
|
|
||||||
]
|
|
||||||
, containerRow =
|
|
||||||
Button.simple
|
|
||||||
++ Color.light
|
|
||||||
++ [ Border.color <| Element.rgb255 186 189 182
|
|
||||||
, Font.alignLeft
|
|
||||||
, Element.paddingXY 8 0
|
|
||||||
, Element.height <| Element.px <|42
|
|
||||||
]
|
|
||||||
++ Grid.simple
|
|
||||||
, input =
|
|
||||||
Color.light
|
|
||||||
++ [ Element.padding 8
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
chipButtonStyle : ButtonStyle msg
|
|
||||||
chipButtonStyle =
|
|
||||||
{ container = Tag.simple
|
|
||||||
, disabled = []
|
|
||||||
, label = Grid.simple
|
|
||||||
, active = Color.primary
|
|
||||||
}
|
|
||||||
|
|
||||||
style : Style
|
|
||||||
{ dialog :
|
|
||||||
{ containerColumn : List (Attribute msg)
|
|
||||||
, title : List (Attribute msg)
|
|
||||||
, buttonRow : List (Attribute msg)
|
|
||||||
, accept : ButtonStyle msg
|
|
||||||
, dismiss : ButtonStyle msg
|
|
||||||
}
|
|
||||||
, button : ButtonStyle msg
|
, button : ButtonStyle msg
|
||||||
, primaryButton : ButtonStyle msg
|
, primaryButton : ButtonStyle msg
|
||||||
, tabButton : ButtonStyle msg
|
, tab : TabStyle msg
|
||||||
, textInput : TextInputStyle msg
|
, textInput : TextInputStyle msg
|
||||||
, chipButton : ButtonStyle msg
|
, chipButton : ButtonStyle msg
|
||||||
} msg
|
, row : RowStyle msg
|
||||||
style =
|
, column : ColumnStyle msg
|
||||||
{ button = buttonStyle
|
, cardColumn : ColumnStyle msg
|
||||||
, primaryButton = simpleButton
|
|
||||||
, tabButton = tabButtonStyle
|
|
||||||
, textInput = textInputStyle
|
|
||||||
, chipButton = chipButtonStyle
|
|
||||||
, dialog =
|
|
||||||
{ containerColumn =
|
|
||||||
Card.simple
|
|
||||||
++ Grid.simple
|
|
||||||
++ [ Element.width <| Element.minimum 280 <| Element.maximum 560 <| Element.fill ]
|
|
||||||
, title = Heading.h3
|
|
||||||
, buttonRow =
|
|
||||||
Grid.simple ++
|
|
||||||
[ Element.paddingEach
|
|
||||||
{ top = 28
|
|
||||||
, bottom = 0
|
|
||||||
, left = 0
|
|
||||||
, right = 0
|
|
||||||
}
|
|
||||||
]
|
|
||||||
, accept = simpleButton
|
|
||||||
, dismiss = textButton
|
|
||||||
}
|
|
||||||
, snackbar =
|
|
||||||
{ row =
|
|
||||||
Card.simple
|
|
||||||
++ Color.dark
|
|
||||||
++ Grid.simple
|
|
||||||
++ [ Element.paddingXY 8 6
|
|
||||||
, Element.height <| Element.px <|54]
|
|
||||||
, button =
|
|
||||||
{ label = Grid.simple
|
|
||||||
, container = Button.simple ++ Color.dark
|
|
||||||
, disabled = Color.disabled
|
|
||||||
, active = Color.primary
|
|
||||||
}
|
|
||||||
, text = [Element.paddingXY 8 0]
|
|
||||||
}
|
|
||||||
, layout = Framework.responsiveLayout
|
|
||||||
{--\a w ->
|
|
||||||
Html.div []
|
|
||||||
[ Html.node "meta"
|
|
||||||
[ Attributes.attribute "name" "viewport"
|
|
||||||
, Attributes.attribute "content" "width=device-width, initial-scale=1.0"
|
|
||||||
]
|
|
||||||
[]
|
|
||||||
, Element.layoutWith
|
|
||||||
{options = (Element.focusStyle
|
|
||||||
{ borderColor = Nothing
|
|
||||||
, backgroundColor = Nothing
|
|
||||||
, shadow = Nothing
|
|
||||||
}
|
|
||||||
|> List.singleton)
|
|
||||||
}
|
|
||||||
(Framework.layoutAttributes ++ a) <| w
|
|
||||||
]--}
|
|
||||||
, header =
|
|
||||||
Framework.container
|
|
||||||
++ Color.dark
|
|
||||||
++ [ Element.padding <| 0
|
|
||||||
, Element.height <| Element.px <| 42
|
|
||||||
]
|
|
||||||
, menuButton =
|
|
||||||
{ label = Grid.simple
|
|
||||||
, container = Button.simple ++ Group.center ++ Color.dark
|
|
||||||
, disabled = Color.disabled
|
|
||||||
, active = Color.primary
|
|
||||||
}
|
|
||||||
, sheetButton =
|
|
||||||
{ container =
|
|
||||||
Button.fill
|
|
||||||
++ Group.center
|
|
||||||
++ Color.light
|
|
||||||
++ [Font.alignLeft]
|
|
||||||
, label = Grid.simple
|
|
||||||
, disabled = Color.disabled
|
|
||||||
, active = Color.primary
|
|
||||||
}
|
|
||||||
, menuTabButton =
|
|
||||||
{ container =
|
|
||||||
[ Element.height <| Element.px <| 42
|
|
||||||
, Border.widthEach
|
|
||||||
{ top = 0,
|
|
||||||
left = 0,
|
|
||||||
right = 0,
|
|
||||||
bottom = 4
|
|
||||||
}
|
|
||||||
, Element.paddingEach
|
|
||||||
{ top = 12
|
|
||||||
, left = 8
|
|
||||||
, right = 8
|
|
||||||
, bottom = 4
|
|
||||||
}
|
|
||||||
, Border.color Color.black
|
|
||||||
]
|
|
||||||
, label = Grid.simple
|
|
||||||
, disabled = Color.disabled
|
|
||||||
, active = [ Border.color Color.turquoise ]
|
|
||||||
}
|
|
||||||
, sheet =
|
|
||||||
Color.light ++ [ Element.width <| Element.maximum 256 <| Element.fill]
|
|
||||||
, menuIcon =
|
|
||||||
Icons.menu |> Element.html |> Element.el []
|
|
||||||
, moreVerticalIcon =
|
|
||||||
Icons.moreVertical |> Element.html |> Element.el []
|
|
||||||
, spacing = 8
|
|
||||||
, title = Heading.h2
|
|
||||||
, searchIcon =
|
|
||||||
Icons.search |> Element.html |> Element.el []
|
|
||||||
, search =
|
|
||||||
Color.simple ++
|
|
||||||
Card.large ++
|
|
||||||
[Font.color <| Element.rgb255 0 0 0
|
|
||||||
, Element.padding 6
|
|
||||||
, Element.centerY
|
|
||||||
, Element.alignRight
|
|
||||||
]
|
|
||||||
, searchFill =
|
|
||||||
Color.light
|
|
||||||
++ Group.center
|
|
||||||
}
|
}
|
||||||
|
msg
|
291
example/src/Data/Style/ElmUiFramework.elm
Normal file
291
example/src/Data/Style/ElmUiFramework.elm
Normal file
@ -0,0 +1,291 @@
|
|||||||
|
module Data.Style.ElmUiFramework exposing (style)
|
||||||
|
|
||||||
|
import Element exposing (Attribute)
|
||||||
|
import Element.Border as Border
|
||||||
|
import Element.Font as Font
|
||||||
|
import Element.Input as Input
|
||||||
|
import Framework
|
||||||
|
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 Icons
|
||||||
|
import Data.Style exposing (Style)
|
||||||
|
import Widget.Style exposing (ButtonStyle, DialogStyle, ExpansionPanelStyle,
|
||||||
|
SnackbarStyle ,RowStyle,ColumnStyle,TextInputStyle,TabStyle)
|
||||||
|
|
||||||
|
textButton : ButtonStyle msg
|
||||||
|
textButton =
|
||||||
|
{ container = Button.simple
|
||||||
|
, labelRow = Grid.simple
|
||||||
|
, ifDisabled = Color.disabled
|
||||||
|
, ifActive = Color.primary
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
simpleButton : ButtonStyle msg
|
||||||
|
simpleButton =
|
||||||
|
{ container = Button.simple ++ Color.primary
|
||||||
|
, labelRow = Grid.simple
|
||||||
|
, ifDisabled = Color.disabled
|
||||||
|
, ifActive = Color.primary
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
menuTabButton : ButtonStyle msg
|
||||||
|
menuTabButton =
|
||||||
|
{ container =
|
||||||
|
[ Element.height <| Element.px <| 42
|
||||||
|
, Border.widthEach
|
||||||
|
{ top = 0
|
||||||
|
, left = 0
|
||||||
|
, right = 0
|
||||||
|
, bottom = 4
|
||||||
|
}
|
||||||
|
, Element.paddingEach
|
||||||
|
{ top = 12
|
||||||
|
, left = 8
|
||||||
|
, right = 8
|
||||||
|
, bottom = 4
|
||||||
|
}
|
||||||
|
, Border.color Color.black
|
||||||
|
]
|
||||||
|
, labelRow = Grid.simple
|
||||||
|
, ifDisabled = Color.disabled
|
||||||
|
, ifActive = [ Border.color Color.turquoise ]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
menuButton : ButtonStyle msg
|
||||||
|
menuButton =
|
||||||
|
{ labelRow = Grid.simple
|
||||||
|
, container = Button.simple ++ Group.center ++ Color.dark
|
||||||
|
, ifDisabled = Color.disabled
|
||||||
|
, ifActive = Color.primary
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sheetButton : ButtonStyle msg
|
||||||
|
sheetButton =
|
||||||
|
{ container =
|
||||||
|
Button.fill
|
||||||
|
++ Group.center
|
||||||
|
++ Color.light
|
||||||
|
++ [ Font.alignLeft ]
|
||||||
|
, labelRow = Grid.simple
|
||||||
|
, ifDisabled = Color.disabled
|
||||||
|
, ifActive = Color.primary
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
buttonStyle : ButtonStyle msg
|
||||||
|
buttonStyle =
|
||||||
|
{ labelRow = [ Element.spacing 8 ]
|
||||||
|
, container = Button.simple
|
||||||
|
, ifDisabled = Color.disabled
|
||||||
|
, ifActive = Color.primary
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
snackbarButton : ButtonStyle msg
|
||||||
|
snackbarButton =
|
||||||
|
{ labelRow = Grid.simple
|
||||||
|
, container = Button.simple ++ Color.dark
|
||||||
|
, ifDisabled = Color.disabled
|
||||||
|
, ifActive = Color.primary
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
tabButtonStyle : ButtonStyle msg
|
||||||
|
tabButtonStyle =
|
||||||
|
{ labelRow = [ Element.spacing 8 ]
|
||||||
|
, container = Button.simple ++ Group.top
|
||||||
|
, ifDisabled = Color.disabled
|
||||||
|
, ifActive = Color.primary
|
||||||
|
}
|
||||||
|
|
||||||
|
textInputStyle : TextInputStyle msg
|
||||||
|
textInputStyle =
|
||||||
|
{ chipButton = chipButtonStyle
|
||||||
|
, chipsRow =
|
||||||
|
[ Element.width <| Element.shrink
|
||||||
|
, Element.spacing <| 4
|
||||||
|
, Element.paddingEach
|
||||||
|
{ top = 8
|
||||||
|
, left = 0
|
||||||
|
, right = 0
|
||||||
|
, bottom = 8
|
||||||
|
}
|
||||||
|
]
|
||||||
|
, containerRow =
|
||||||
|
Button.simple
|
||||||
|
++ Color.light
|
||||||
|
++ [ Border.color <| Element.rgb255 186 189 182
|
||||||
|
, Font.alignLeft
|
||||||
|
, Element.paddingXY 8 0
|
||||||
|
, Element.height <| Element.px <| 42
|
||||||
|
]
|
||||||
|
++ Grid.simple
|
||||||
|
, input =
|
||||||
|
Color.light
|
||||||
|
++ [ Element.padding 8
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
chipButtonStyle : ButtonStyle msg
|
||||||
|
chipButtonStyle =
|
||||||
|
{ container = Tag.simple
|
||||||
|
, ifDisabled = []
|
||||||
|
, labelRow = Grid.simple
|
||||||
|
, ifActive = Color.primary
|
||||||
|
}
|
||||||
|
|
||||||
|
expansionPanelStyle : ExpansionPanelStyle msg
|
||||||
|
expansionPanelStyle =
|
||||||
|
{ containerColumn = Card.simple ++ Grid.simple ++ [Element.height <| Element.shrink]
|
||||||
|
, panelRow = Grid.spacedEvenly ++ [Element.height <| Element.shrink]
|
||||||
|
, labelRow = Grid.simple ++ [Element.height <| Element.shrink]
|
||||||
|
, content = []
|
||||||
|
, expandIcon = Icons.chevronDown |> Element.html |> Element.el []
|
||||||
|
, collapseIcon = Icons.chevronUp |> Element.html |> Element.el []
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
dialog : DialogStyle msg
|
||||||
|
dialog =
|
||||||
|
{ containerColumn =
|
||||||
|
Card.simple
|
||||||
|
++ Grid.simple
|
||||||
|
++ [ Element.centerY
|
||||||
|
, Element.width <| Element.minimum 280 <| Element.maximum 560 <| Element.fill
|
||||||
|
]
|
||||||
|
, title = Heading.h3
|
||||||
|
, buttonRow =
|
||||||
|
Grid.simple
|
||||||
|
++ [ Element.paddingEach
|
||||||
|
{ top = 28
|
||||||
|
, bottom = 0
|
||||||
|
, left = 0
|
||||||
|
, right = 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
, acceptButton = simpleButton
|
||||||
|
, dismissButton = textButton
|
||||||
|
}
|
||||||
|
|
||||||
|
snackbar : SnackbarStyle msg
|
||||||
|
snackbar =
|
||||||
|
{ containerRow =
|
||||||
|
Card.simple
|
||||||
|
++ Color.dark
|
||||||
|
++ Grid.simple
|
||||||
|
++ [ Element.paddingXY 8 6
|
||||||
|
, Element.height <| Element.px <| 54
|
||||||
|
]
|
||||||
|
, button = snackbarButton
|
||||||
|
, text = [ Element.paddingXY 8 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
tab : TabStyle msg
|
||||||
|
tab =
|
||||||
|
{ button = tabButtonStyle
|
||||||
|
, optionRow = Grid.simple
|
||||||
|
, containerColumn = Grid.compact
|
||||||
|
, content = (Card.small ++ Group.bottom)
|
||||||
|
}
|
||||||
|
|
||||||
|
row : RowStyle msg
|
||||||
|
row =
|
||||||
|
{ containerRow = Grid.compact
|
||||||
|
, element = []
|
||||||
|
, ifFirst = Group.left
|
||||||
|
, ifLast = Group.right
|
||||||
|
, ifCenter = Group.center
|
||||||
|
}
|
||||||
|
|
||||||
|
cardColumn : ColumnStyle msg
|
||||||
|
cardColumn =
|
||||||
|
{ containerColumn = Grid.compact
|
||||||
|
, element = Card.large ++ [Element.height <| Element.fill]
|
||||||
|
, ifFirst = Group.top
|
||||||
|
, ifLast = Group.bottom
|
||||||
|
, ifCenter = Group.center
|
||||||
|
}
|
||||||
|
|
||||||
|
column : ColumnStyle msg
|
||||||
|
column =
|
||||||
|
{ containerColumn = Grid.compact
|
||||||
|
, element = []
|
||||||
|
, ifFirst = Group.top
|
||||||
|
, ifLast = Group.bottom
|
||||||
|
, ifCenter =Group.center
|
||||||
|
}
|
||||||
|
|
||||||
|
style : Style msg
|
||||||
|
style =
|
||||||
|
{ row = row
|
||||||
|
, cardColumn = cardColumn
|
||||||
|
, column = column
|
||||||
|
, button = buttonStyle
|
||||||
|
, primaryButton = simpleButton
|
||||||
|
, tab = tab
|
||||||
|
, textInput = textInputStyle
|
||||||
|
, chipButton = chipButtonStyle
|
||||||
|
, expansionPanel = expansionPanelStyle
|
||||||
|
, dialog = dialog
|
||||||
|
, snackbar = snackbar
|
||||||
|
, layout = Framework.responsiveLayout
|
||||||
|
|
||||||
|
{--\a w ->
|
||||||
|
Html.div []
|
||||||
|
[ Html.node "meta"
|
||||||
|
[ Attributes.attribute "name" "viewport"
|
||||||
|
, Attributes.attribute "content" "width=device-width, initial-scale=1.0"
|
||||||
|
]
|
||||||
|
[]
|
||||||
|
, Element.layoutWith
|
||||||
|
{options = (Element.focusStyle
|
||||||
|
{ borderColor = Nothing
|
||||||
|
, backgroundColor = Nothing
|
||||||
|
, shadow = Nothing
|
||||||
|
}
|
||||||
|
|> List.singleton)
|
||||||
|
}
|
||||||
|
(Framework.layoutAttributes ++ a) <| w
|
||||||
|
]--}
|
||||||
|
, header =
|
||||||
|
Framework.container
|
||||||
|
++ Color.dark
|
||||||
|
++ [ Element.padding <| 0
|
||||||
|
, Element.height <| Element.px <| 42
|
||||||
|
]
|
||||||
|
, menuButton = menuButton
|
||||||
|
, sheetButton = sheetButton
|
||||||
|
, menuTabButton = menuTabButton
|
||||||
|
, sheet =
|
||||||
|
Color.light ++ [ Element.width <| Element.maximum 256 <| Element.fill ]
|
||||||
|
, menuIcon =
|
||||||
|
Icons.menu |> Element.html |> Element.el []
|
||||||
|
, moreVerticalIcon =
|
||||||
|
Icons.moreVertical |> Element.html |> Element.el []
|
||||||
|
, spacing = 8
|
||||||
|
, title = Heading.h2
|
||||||
|
, searchIcon =
|
||||||
|
Icons.search |> Element.html |> Element.el []
|
||||||
|
, search =
|
||||||
|
Color.simple
|
||||||
|
++ Card.large
|
||||||
|
++ [ Font.color <| Element.rgb255 0 0 0
|
||||||
|
, Element.padding 6
|
||||||
|
, Element.centerY
|
||||||
|
, Element.alignRight
|
||||||
|
]
|
||||||
|
, searchFill =
|
||||||
|
Color.light ++ Group.center
|
||||||
|
}
|
142
example/src/Data/Style/Template.elm
Normal file
142
example/src/Data/Style/Template.elm
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
module Data.Style.Template exposing (style)
|
||||||
|
|
||||||
|
import Data.Style exposing (Style)
|
||||||
|
import Element exposing (Attribute,Element)
|
||||||
|
import Element.Border as Border
|
||||||
|
import Element.Font as Font
|
||||||
|
import Element.Background as Background
|
||||||
|
import Widget.Style exposing (ButtonStyle, DialogStyle, ExpansionPanelStyle,
|
||||||
|
SnackbarStyle ,TextInputStyle,TabStyle,ColumnStyle,RowStyle)
|
||||||
|
|
||||||
|
|
||||||
|
fontSize : Int
|
||||||
|
fontSize = 10
|
||||||
|
|
||||||
|
box : String -> List (Attribute msg)
|
||||||
|
box string =
|
||||||
|
[ Border.width 1
|
||||||
|
, Background.color <| Element.rgba 1 1 1 0.5
|
||||||
|
, Element.padding 10
|
||||||
|
, Element.spacing 10
|
||||||
|
, Element.above <|
|
||||||
|
Element.el [Font.size <| fontSize] <|
|
||||||
|
Element.text string
|
||||||
|
]
|
||||||
|
|
||||||
|
decoration : String -> List (Attribute msg)
|
||||||
|
decoration string =
|
||||||
|
[ Element.below <|
|
||||||
|
Element.el [Font.size <| fontSize] <|
|
||||||
|
Element.text string
|
||||||
|
, Background.color <| Element.rgb 0.66 0.66 0.66
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
icon : String -> Element msg
|
||||||
|
icon string =
|
||||||
|
Element.none
|
||||||
|
|> Element.el
|
||||||
|
[ Element.width <| Element.px 12
|
||||||
|
, Element.height <| Element.px 12
|
||||||
|
, Border.rounded 6
|
||||||
|
, Border.width 1
|
||||||
|
, Element.above <|
|
||||||
|
Element.el [Font.size <| fontSize] <|
|
||||||
|
Element.text string
|
||||||
|
]
|
||||||
|
|
||||||
|
button : String -> ButtonStyle msg
|
||||||
|
button string =
|
||||||
|
{ container = box <| string ++ ":container"
|
||||||
|
, labelRow = box <| string ++ ":labelRow"
|
||||||
|
, ifDisabled = decoration <| string ++ ":ifDisabled"
|
||||||
|
, ifActive = decoration <| string ++ ":ifActive"
|
||||||
|
}
|
||||||
|
|
||||||
|
snackbar : String -> SnackbarStyle msg
|
||||||
|
snackbar string =
|
||||||
|
{ containerRow = box <| string ++ ":containerRow"
|
||||||
|
, button = button <| string ++ ":button"
|
||||||
|
, text = box <| string ++ ":text"
|
||||||
|
}
|
||||||
|
|
||||||
|
dialog : String -> DialogStyle msg
|
||||||
|
dialog string =
|
||||||
|
{ containerColumn = box <| string ++ ":containerColumn"
|
||||||
|
, title = box <| string ++ ":title"
|
||||||
|
, buttonRow = box <| string ++ ":buttonRow"
|
||||||
|
, acceptButton = button <| string ++ ":acceptButton"
|
||||||
|
, dismissButton = button <| string ++ ":dismissButton"
|
||||||
|
}
|
||||||
|
|
||||||
|
expansionPanel : String -> ExpansionPanelStyle msg
|
||||||
|
expansionPanel string =
|
||||||
|
{ containerColumn = box <| string ++ ":containerColumn"
|
||||||
|
, panelRow = box <| string ++ ":panelRow"
|
||||||
|
, labelRow = box <| string ++ ":labelRow"
|
||||||
|
, content = box <| string ++ ":content"
|
||||||
|
, expandIcon = icon <| string ++ ":expandIcon"
|
||||||
|
, collapseIcon = icon <| string ++ ":collapseIcon"
|
||||||
|
}
|
||||||
|
|
||||||
|
textInput : String -> TextInputStyle msg
|
||||||
|
textInput string =
|
||||||
|
{ chipButton = button <| string ++ ":chipButton"
|
||||||
|
, chipsRow = box <| string ++ ":chipsRow"
|
||||||
|
, containerRow = box <| string ++ ":containerRow"
|
||||||
|
, input = box <| string ++ ":input"
|
||||||
|
}
|
||||||
|
|
||||||
|
tab : String -> TabStyle msg
|
||||||
|
tab string =
|
||||||
|
{ button = button <| string ++ ":button"
|
||||||
|
, optionRow = box <| string ++ ":optionRow"
|
||||||
|
, containerColumn = box <| string ++ ":containerColumn"
|
||||||
|
, content = box <| string ++ ":content"
|
||||||
|
}
|
||||||
|
|
||||||
|
row : String -> RowStyle msg
|
||||||
|
row string =
|
||||||
|
{ containerRow = box <| string ++ ":containerRow"
|
||||||
|
, element = box <| string ++ ":element"
|
||||||
|
, ifFirst = box <| string ++ ":ifFirst"
|
||||||
|
, ifLast = box <| string ++ ":ifLast"
|
||||||
|
, ifCenter = box <| string ++ ":ifCenter"
|
||||||
|
}
|
||||||
|
|
||||||
|
column : String -> ColumnStyle msg
|
||||||
|
column string =
|
||||||
|
{ containerColumn = box <| string ++ ":containerColumn"
|
||||||
|
, element = box <| string ++ ":element"
|
||||||
|
, ifFirst = box <| string ++ ":ifFirst"
|
||||||
|
, ifLast = box <| string ++ ":ifLast"
|
||||||
|
, ifCenter = box <| string ++ ":ifCenter"
|
||||||
|
}
|
||||||
|
|
||||||
|
style :Style msg
|
||||||
|
style =
|
||||||
|
{ row = row <| "row"
|
||||||
|
, cardColumn = column <| "cardRow"
|
||||||
|
, column = column <| "column"
|
||||||
|
, button = button <| "button"
|
||||||
|
, primaryButton = button <| "primaryButton"
|
||||||
|
, tab = tab <| "tab"
|
||||||
|
, textInput = textInput <| "textInput"
|
||||||
|
, chipButton = button <| "chipButton"
|
||||||
|
, expansionPanel = expansionPanel "expansionPanel"
|
||||||
|
, dialog = dialog "dialog"
|
||||||
|
, snackbar = snackbar "snackbar"
|
||||||
|
, layout = Element.layout
|
||||||
|
, header = box "header"
|
||||||
|
, menuButton = button "menuButton"
|
||||||
|
, sheetButton = button "sheetButton"
|
||||||
|
, menuTabButton = button "menuTabButton"
|
||||||
|
, sheet = box "sheet"
|
||||||
|
, menuIcon = icon "menuIcon"
|
||||||
|
, moreVerticalIcon = icon "moreVerticalIcon"
|
||||||
|
, spacing = 8
|
||||||
|
, title = box "title"
|
||||||
|
, searchIcon = icon "searchIcon"
|
||||||
|
, search = box "search"
|
||||||
|
, searchFill = box "searchFill"
|
||||||
|
}
|
17
example/src/Data/Theme.elm
Normal file
17
example/src/Data/Theme.elm
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
module Data.Theme exposing (Theme(..),toStyle)
|
||||||
|
|
||||||
|
import Data.Style exposing (Style)
|
||||||
|
import Data.Style.ElmUiFramework
|
||||||
|
import Data.Style.Template
|
||||||
|
|
||||||
|
type Theme =
|
||||||
|
ElmUiFramework
|
||||||
|
| Template
|
||||||
|
|
||||||
|
toStyle : Theme -> Style msg
|
||||||
|
toStyle theme =
|
||||||
|
case theme of
|
||||||
|
ElmUiFramework ->
|
||||||
|
Data.Style.ElmUiFramework.style
|
||||||
|
Template ->
|
||||||
|
Data.Style.Template.style
|
@ -1,14 +1,15 @@
|
|||||||
module Example exposing (main)
|
module Example exposing (main)
|
||||||
|
|
||||||
|
import Array
|
||||||
import Browser
|
import Browser
|
||||||
import Browser.Dom as Dom exposing (Viewport)
|
import Browser.Dom as Dom exposing (Viewport)
|
||||||
import Browser.Events as Events
|
import Browser.Events as Events
|
||||||
import Browser.Navigation as Navigation
|
import Browser.Navigation as Navigation
|
||||||
import Component
|
import Data.Section as Section exposing (Section(..))
|
||||||
import Element exposing (DeviceClass(..), Element,Attribute)
|
import Element exposing (Attribute, DeviceClass(..), Element)
|
||||||
import Element.Input as Input
|
|
||||||
import Element.Font as Font
|
|
||||||
import Element.Border as Border
|
import Element.Border as Border
|
||||||
|
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
|
||||||
@ -21,25 +22,24 @@ import Framework.Tag as Tag
|
|||||||
import Html exposing (Html)
|
import Html exposing (Html)
|
||||||
import Html.Attributes as Attributes
|
import Html.Attributes as Attributes
|
||||||
import Icons
|
import Icons
|
||||||
import Layout exposing (Part, Layout)
|
import Layout exposing (Layout, Part)
|
||||||
import Data.Style exposing (style)
|
|
||||||
import Reusable
|
import Reusable
|
||||||
import Set exposing (Set)
|
import Set exposing (Set)
|
||||||
import Stateless
|
import Stateless
|
||||||
import Task
|
import Task
|
||||||
import Time
|
import Time
|
||||||
import Widget
|
import Widget
|
||||||
import Widget.Style exposing (ButtonStyle)
|
|
||||||
import Widget.FilterSelect as FilterSelect
|
|
||||||
import Widget.ScrollingNav as ScrollingNav
|
import Widget.ScrollingNav as ScrollingNav
|
||||||
import Widget.Snackbar as Snackbar
|
import Widget.Snackbar as Snackbar
|
||||||
import Widget.ValidatedInput as ValidatedInput
|
import Widget.Style exposing (ButtonStyle)
|
||||||
import Data.Section as Section exposing (Section(..))
|
import Data.Style as Style exposing (Style)
|
||||||
import Array
|
import Data.Theme as Theme exposing (Theme(..))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
type alias LoadedModel =
|
type alias LoadedModel =
|
||||||
{ component : Component.Model
|
{ stateless : Stateless.Model
|
||||||
, stateless : Stateless.Model
|
|
||||||
, reusable : Reusable.Model
|
, reusable : Reusable.Model
|
||||||
, scrollingNav : ScrollingNav.Model Section
|
, scrollingNav : ScrollingNav.Model Section
|
||||||
, layout : Layout LoadedMsg
|
, layout : Layout LoadedMsg
|
||||||
@ -50,6 +50,7 @@ type alias LoadedModel =
|
|||||||
, current : String
|
, current : String
|
||||||
, remaining : Int
|
, remaining : Int
|
||||||
}
|
}
|
||||||
|
, theme : Theme
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -61,16 +62,16 @@ type Model
|
|||||||
type LoadedMsg
|
type LoadedMsg
|
||||||
= StatelessSpecific Stateless.Msg
|
= StatelessSpecific Stateless.Msg
|
||||||
| ReusableSpecific Reusable.Msg
|
| ReusableSpecific Reusable.Msg
|
||||||
| ComponentSpecific Component.Msg
|
|
||||||
| UpdateScrollingNav (ScrollingNav.Model Section -> ScrollingNav.Model Section)
|
| UpdateScrollingNav (ScrollingNav.Model Section -> ScrollingNav.Model Section)
|
||||||
| TimePassed Int
|
| TimePassed Int
|
||||||
| AddSnackbar (String,Bool)
|
| AddSnackbar ( String, Bool )
|
||||||
| ToggleDialog Bool
|
| ToggleDialog Bool
|
||||||
| ChangedSidebar (Maybe Part)
|
| ChangedSidebar (Maybe Part)
|
||||||
| Resized { width : Int, height : Int }
|
| Resized { width : Int, height : Int }
|
||||||
| Load String
|
| Load String
|
||||||
| JumpTo Section
|
| JumpTo Section
|
||||||
| ChangedSearch String
|
| ChangedSearch String
|
||||||
|
| SetTheme Theme
|
||||||
| Idle
|
| Idle
|
||||||
|
|
||||||
|
|
||||||
@ -87,16 +88,17 @@ initialModel { viewport } =
|
|||||||
{ toString = Section.toString
|
{ toString = Section.toString
|
||||||
, fromString = Section.fromString
|
, fromString = Section.fromString
|
||||||
, arrangement = Section.asList
|
, arrangement = Section.asList
|
||||||
, toMsg = \result ->
|
, toMsg =
|
||||||
|
\result ->
|
||||||
case result of
|
case result of
|
||||||
Ok fun ->
|
Ok fun ->
|
||||||
UpdateScrollingNav fun
|
UpdateScrollingNav fun
|
||||||
|
|
||||||
Err _ ->
|
Err _ ->
|
||||||
Idle
|
Idle
|
||||||
}
|
}
|
||||||
in
|
in
|
||||||
( { component = Component.init
|
( { stateless = Stateless.init
|
||||||
, stateless = Stateless.init
|
|
||||||
, reusable = Reusable.init
|
, reusable = Reusable.init
|
||||||
, scrollingNav = scrollingNav
|
, scrollingNav = scrollingNav
|
||||||
, layout = Layout.init
|
, layout = Layout.init
|
||||||
@ -110,6 +112,7 @@ initialModel { viewport } =
|
|||||||
, current = ""
|
, current = ""
|
||||||
, remaining = 0
|
, remaining = 0
|
||||||
}
|
}
|
||||||
|
, theme = ElmUiFramework
|
||||||
}
|
}
|
||||||
, cmd
|
, cmd
|
||||||
)
|
)
|
||||||
@ -124,11 +127,17 @@ init () =
|
|||||||
|
|
||||||
view : Model -> Html Msg
|
view : Model -> Html Msg
|
||||||
view model =
|
view model =
|
||||||
|
|
||||||
case model of
|
case model of
|
||||||
Loading ->
|
Loading ->
|
||||||
Element.none |> Framework.responsiveLayout []
|
Element.none |> Framework.responsiveLayout []
|
||||||
|
|
||||||
Loaded m ->
|
Loaded m ->
|
||||||
|
let
|
||||||
|
style : Style msg
|
||||||
|
style =
|
||||||
|
Theme.toStyle m.theme
|
||||||
|
in
|
||||||
Html.map LoadedSpecific <|
|
Html.map LoadedSpecific <|
|
||||||
Layout.view []
|
Layout.view []
|
||||||
{ dialog =
|
{ dialog =
|
||||||
@ -139,11 +148,13 @@ view model =
|
|||||||
|> List.singleton
|
|> List.singleton
|
||||||
|> Element.paragraph []
|
|> Element.paragraph []
|
||||||
, title = Just "Dialog"
|
, title = Just "Dialog"
|
||||||
, accept = Just
|
, accept =
|
||||||
|
Just
|
||||||
{ text = "Ok"
|
{ text = "Ok"
|
||||||
, onPress = Just <| ToggleDialog False
|
, onPress = Just <| ToggleDialog False
|
||||||
}
|
}
|
||||||
, dismiss = Just
|
, dismiss =
|
||||||
|
Just
|
||||||
{ text = "Dismiss"
|
{ text = "Dismiss"
|
||||||
, onPress = Just <| ToggleDialog False
|
, onPress = Just <| ToggleDialog False
|
||||||
}
|
}
|
||||||
@ -158,57 +169,55 @@ view model =
|
|||||||
, [ m.scrollingNav
|
, [ m.scrollingNav
|
||||||
|> ScrollingNav.view
|
|> ScrollingNav.view
|
||||||
(\section ->
|
(\section ->
|
||||||
( case section of
|
(case section of
|
||||||
ComponentViews ->
|
|
||||||
m.component
|
|
||||||
|> Component.view ComponentSpecific
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ReusableViews ->
|
ReusableViews ->
|
||||||
Reusable.view
|
Reusable.view m.theme
|
||||||
{ addSnackbar = AddSnackbar
|
{ addSnackbar = AddSnackbar
|
||||||
, model = m.reusable
|
, model = m.reusable
|
||||||
, msgMapper = ReusableSpecific
|
, msgMapper = ReusableSpecific
|
||||||
}
|
}
|
||||||
|
|
||||||
StatelessViews ->
|
StatelessViews ->
|
||||||
Stateless.view
|
Stateless.view m.theme
|
||||||
{ msgMapper = StatelessSpecific
|
{ msgMapper = StatelessSpecific
|
||||||
, showDialog = ToggleDialog True
|
, showDialog = ToggleDialog True
|
||||||
, changedSheet = ChangedSidebar
|
, changedSheet = ChangedSidebar
|
||||||
}
|
}
|
||||||
m.stateless
|
m.stateless
|
||||||
) |> (\{title,description,items} ->
|
)
|
||||||
|
|> (\{ title, description, items } ->
|
||||||
[ Element.el Heading.h2 <| Element.text <| title
|
[ Element.el Heading.h2 <| Element.text <| title
|
||||||
, if m.search.current == "" then
|
, if m.search.current == "" then
|
||||||
description
|
description
|
||||||
|> Element.text
|
|> Element.text
|
||||||
|> List.singleton
|
|> List.singleton
|
||||||
|> Element.paragraph []
|
|> Element.paragraph []
|
||||||
else Element.none
|
|
||||||
|
else
|
||||||
|
Element.none
|
||||||
, items
|
, items
|
||||||
|> (if m.search.current /= "" then
|
|> (if m.search.current /= "" then
|
||||||
List.filter
|
List.filter
|
||||||
( Tuple.first
|
(\(a,_,_) ->
|
||||||
>> String.toLower
|
a
|
||||||
>> String.contains (m.search.current |> String.toLower)
|
|> String.toLower
|
||||||
|
|> String.contains (m.search.current |> String.toLower)
|
||||||
)
|
)
|
||||||
|
|
||||||
else
|
else
|
||||||
identity)
|
identity
|
||||||
|
)
|
||||||
|> List.map
|
|> List.map
|
||||||
(\(name,elem) ->
|
(\( name, elem, more ) ->
|
||||||
[ Element.text name
|
[ Element.text name
|
||||||
|> Element.el Heading.h3
|
|> Element.el Heading.h3
|
||||||
, elem
|
, elem
|
||||||
|
, more
|
||||||
]
|
]
|
||||||
|> Element.column
|
|> Widget.column style.cardColumn
|
||||||
(Grid.simple
|
|
||||||
++ Card.large
|
|
||||||
++ [Element.height <| Element.fill])
|
|
||||||
)
|
)
|
||||||
|> Element.wrappedRow
|
|> Element.wrappedRow
|
||||||
(Grid.simple ++ [Element.height <| Element.shrink])
|
(Grid.simple ++ [ Element.height <| Element.shrink ])
|
||||||
]
|
]
|
||||||
|> Element.column (Grid.section ++ [ Element.centerX ])
|
|> Element.column (Grid.section ++ [ Element.centerX ])
|
||||||
)
|
)
|
||||||
@ -217,7 +226,7 @@ view model =
|
|||||||
|> Element.column Framework.container
|
|> Element.column Framework.container
|
||||||
]
|
]
|
||||||
|> Element.column Grid.compact
|
|> Element.column Grid.compact
|
||||||
, style = style
|
, style =style
|
||||||
, layout = m.layout
|
, layout = m.layout
|
||||||
, window = m.window
|
, window = m.window
|
||||||
, menu =
|
, menu =
|
||||||
@ -232,23 +241,37 @@ view model =
|
|||||||
, actions =
|
, actions =
|
||||||
[ { onPress = Just <| Load "https://package.elm-lang.org/packages/Orasund/elm-ui-widgets/latest/"
|
[ { onPress = Just <| Load "https://package.elm-lang.org/packages/Orasund/elm-ui-widgets/latest/"
|
||||||
, text = "Docs"
|
, text = "Docs"
|
||||||
, icon = Icons.book|> Element.html |> Element.el []
|
, icon = Icons.book |> Element.html |> Element.el []
|
||||||
}
|
}
|
||||||
, { onPress = Just <| Load "https://github.com/Orasund/elm-ui-widgets"
|
, { onPress = Just <| Load "https://github.com/Orasund/elm-ui-widgets"
|
||||||
, text = "Github"
|
, text = "Github"
|
||||||
, icon = Icons.github|> Element.html |> Element.el []
|
, icon = Icons.github |> Element.html |> Element.el []
|
||||||
|
}
|
||||||
|
, { 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
|
||||||
|
Just <| SetTheme <| Template
|
||||||
|
else
|
||||||
|
Nothing
|
||||||
|
, text = "Template Theme"
|
||||||
|
, icon = Icons.penTool |> Element.html |> Element.el []
|
||||||
}
|
}
|
||||||
, { onPress = Nothing
|
, { onPress = Nothing
|
||||||
, text = "Placeholder"
|
, text = "Placeholder"
|
||||||
, icon = Icons.circle|> Element.html |> Element.el []
|
, icon = Icons.circle |> Element.html |> Element.el []
|
||||||
}
|
}
|
||||||
, { onPress = Nothing
|
, { onPress = Nothing
|
||||||
, text = "Placeholder"
|
, text = "Placeholder"
|
||||||
, icon = Icons.triangle|> Element.html |> Element.el []
|
, icon = Icons.triangle |> Element.html |> Element.el []
|
||||||
}
|
}
|
||||||
, { onPress = Nothing
|
, { onPress = Nothing
|
||||||
, text = "Placeholder"
|
, text = "Placeholder"
|
||||||
, icon = Icons.square|> Element.html |> Element.el []
|
, icon = Icons.square |> Element.html |> Element.el []
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
, onChangedSidebar = ChangedSidebar
|
, onChangedSidebar = ChangedSidebar
|
||||||
@ -268,17 +291,6 @@ view model =
|
|||||||
updateLoaded : LoadedMsg -> LoadedModel -> ( LoadedModel, Cmd LoadedMsg )
|
updateLoaded : LoadedMsg -> LoadedModel -> ( LoadedModel, Cmd LoadedMsg )
|
||||||
updateLoaded msg model =
|
updateLoaded msg model =
|
||||||
case msg of
|
case msg of
|
||||||
ComponentSpecific m ->
|
|
||||||
model.component
|
|
||||||
|> Component.update m
|
|
||||||
|> Tuple.mapBoth
|
|
||||||
(\component ->
|
|
||||||
{ model
|
|
||||||
| component = component
|
|
||||||
}
|
|
||||||
)
|
|
||||||
(Cmd.map ComponentSpecific)
|
|
||||||
|
|
||||||
ReusableSpecific m ->
|
ReusableSpecific m ->
|
||||||
( model.reusable
|
( model.reusable
|
||||||
|> Reusable.update m
|
|> Reusable.update m
|
||||||
@ -302,13 +314,14 @@ updateLoaded msg model =
|
|||||||
(Cmd.map StatelessSpecific)
|
(Cmd.map StatelessSpecific)
|
||||||
|
|
||||||
UpdateScrollingNav fun ->
|
UpdateScrollingNav fun ->
|
||||||
( { model | scrollingNav = model.scrollingNav |> fun}
|
( { model | scrollingNav = model.scrollingNav |> fun }
|
||||||
, Cmd.none
|
, Cmd.none
|
||||||
)
|
)
|
||||||
|
|
||||||
TimePassed int ->
|
TimePassed int ->
|
||||||
let
|
let
|
||||||
search = model.search
|
search =
|
||||||
|
model.search
|
||||||
in
|
in
|
||||||
( { model
|
( { model
|
||||||
| layout = model.layout |> Layout.timePassed int
|
| layout = model.layout |> Layout.timePassed int
|
||||||
@ -319,10 +332,12 @@ updateLoaded msg model =
|
|||||||
| current = search.raw
|
| current = search.raw
|
||||||
, remaining = 0
|
, remaining = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{ search
|
{ search
|
||||||
| remaining = search.remaining - int
|
| remaining = search.remaining - int
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
model.search
|
model.search
|
||||||
}
|
}
|
||||||
@ -330,17 +345,21 @@ updateLoaded msg model =
|
|||||||
|> Task.perform UpdateScrollingNav
|
|> Task.perform UpdateScrollingNav
|
||||||
)
|
)
|
||||||
|
|
||||||
AddSnackbar (string,bool) ->
|
AddSnackbar ( string, bool ) ->
|
||||||
( { model
|
( { model
|
||||||
| layout = model.layout
|
| layout =
|
||||||
|
model.layout
|
||||||
|> Layout.queueMessage
|
|> Layout.queueMessage
|
||||||
{ text = string
|
{ text = string
|
||||||
, button = if bool then
|
, button =
|
||||||
|
if bool then
|
||||||
Just
|
Just
|
||||||
{ text = "Add"
|
{ text = "Add"
|
||||||
, onPress = Just <|
|
, onPress =
|
||||||
(AddSnackbar ("This is another message", False))
|
Just <|
|
||||||
|
AddSnackbar ( "This is another message", False )
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
Nothing
|
Nothing
|
||||||
}
|
}
|
||||||
@ -364,7 +383,7 @@ updateLoaded msg model =
|
|||||||
)
|
)
|
||||||
|
|
||||||
Load string ->
|
Load string ->
|
||||||
( model, Navigation.load string)
|
( model, Navigation.load string )
|
||||||
|
|
||||||
JumpTo section ->
|
JumpTo section ->
|
||||||
( model
|
( model
|
||||||
@ -377,9 +396,11 @@ updateLoaded msg model =
|
|||||||
|
|
||||||
ChangedSearch string ->
|
ChangedSearch string ->
|
||||||
let
|
let
|
||||||
search = model.search
|
search =
|
||||||
|
model.search
|
||||||
in
|
in
|
||||||
( { model | search =
|
( { model
|
||||||
|
| search =
|
||||||
{ search
|
{ search
|
||||||
| raw = string
|
| raw = string
|
||||||
, remaining = 300
|
, remaining = 300
|
||||||
@ -388,8 +409,13 @@ updateLoaded msg model =
|
|||||||
, Cmd.none
|
, Cmd.none
|
||||||
)
|
)
|
||||||
|
|
||||||
|
SetTheme theme ->
|
||||||
|
( { model | theme = theme }
|
||||||
|
, Cmd.none
|
||||||
|
)
|
||||||
|
|
||||||
Idle ->
|
Idle ->
|
||||||
( model , Cmd.none)
|
( model, Cmd.none )
|
||||||
|
|
||||||
|
|
||||||
update : Msg -> Model -> ( Model, Cmd Msg )
|
update : Msg -> Model -> ( Model, Cmd Msg )
|
||||||
|
@ -1,17 +1,19 @@
|
|||||||
module Icons exposing
|
module Icons exposing
|
||||||
( book
|
( book
|
||||||
|
, chevronDown
|
||||||
|
, chevronLeft
|
||||||
|
, chevronRight
|
||||||
|
, circle
|
||||||
, github
|
, github
|
||||||
, menu
|
, menu
|
||||||
, moreVertical
|
, moreVertical
|
||||||
, circle
|
, repeat
|
||||||
, triangle
|
|
||||||
, square
|
|
||||||
, search
|
, search
|
||||||
, slash
|
, slash
|
||||||
, repeat
|
, square
|
||||||
, chevronDown
|
, triangle
|
||||||
, chevronRight
|
, chevronUp
|
||||||
, chevronLeft
|
, penTool
|
||||||
)
|
)
|
||||||
|
|
||||||
import Html exposing (Html)
|
import Html exposing (Html)
|
||||||
@ -33,6 +35,7 @@ svgFeatherIcon className =
|
|||||||
, width "16"
|
, width "16"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
chevronDown : Html msg
|
chevronDown : Html msg
|
||||||
chevronDown =
|
chevronDown =
|
||||||
svgFeatherIcon "chevron-down"
|
svgFeatherIcon "chevron-down"
|
||||||
@ -45,12 +48,20 @@ chevronRight =
|
|||||||
svgFeatherIcon "chevron-right"
|
svgFeatherIcon "chevron-right"
|
||||||
[ Svg.polyline [ points "9 18 15 12 9 6" ] []
|
[ Svg.polyline [ points "9 18 15 12 9 6" ] []
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
chevronLeft : Html msg
|
chevronLeft : Html msg
|
||||||
chevronLeft =
|
chevronLeft =
|
||||||
svgFeatherIcon "chevron-left"
|
svgFeatherIcon "chevron-left"
|
||||||
[ Svg.polyline [ points "15 18 9 12 15 6" ] []
|
[ Svg.polyline [ points "15 18 9 12 15 6" ] []
|
||||||
]
|
]
|
||||||
|
|
||||||
|
chevronUp : Html msg
|
||||||
|
chevronUp =
|
||||||
|
svgFeatherIcon "chevron-up"
|
||||||
|
[ Svg.polyline [ points "18 15 12 9 6 15" ] []
|
||||||
|
]
|
||||||
|
|
||||||
repeat : Html msg
|
repeat : Html msg
|
||||||
repeat =
|
repeat =
|
||||||
svgFeatherIcon "repeat"
|
svgFeatherIcon "repeat"
|
||||||
@ -60,6 +71,14 @@ repeat =
|
|||||||
, Svg.path [ d "M21 13v2a4 4 0 0 1-4 4H3" ] []
|
, Svg.path [ d "M21 13v2a4 4 0 0 1-4 4H3" ] []
|
||||||
]
|
]
|
||||||
|
|
||||||
|
penTool : Html msg
|
||||||
|
penTool =
|
||||||
|
svgFeatherIcon "pen-tool"
|
||||||
|
[ Svg.path [ d "M12 19l7-7 3 3-7 7-3-3z" ] []
|
||||||
|
, Svg.path [ d "M18 13l-1.5-7.5L2 2l3.5 14.5L13 18l5-5z" ] []
|
||||||
|
, Svg.path [ d "M2 2l7.586 7.586" ] []
|
||||||
|
, Svg.circle [ cx "11", cy "11", r "2" ] []
|
||||||
|
]
|
||||||
|
|
||||||
book : Html msg
|
book : Html msg
|
||||||
book =
|
book =
|
||||||
@ -84,6 +103,7 @@ menu =
|
|||||||
, Svg.line [ x1 "3", y1 "18", x2 "21", y2 "18" ] []
|
, Svg.line [ x1 "3", y1 "18", x2 "21", y2 "18" ] []
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
moreVertical : Html msg
|
moreVertical : Html msg
|
||||||
moreVertical =
|
moreVertical =
|
||||||
svgFeatherIcon "more-vertical"
|
svgFeatherIcon "more-vertical"
|
||||||
@ -92,12 +112,14 @@ moreVertical =
|
|||||||
, Svg.circle [ cx "12", cy "19", r "1" ] []
|
, Svg.circle [ cx "12", cy "19", r "1" ] []
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
circle : Html msg
|
circle : Html msg
|
||||||
circle =
|
circle =
|
||||||
svgFeatherIcon "circle"
|
svgFeatherIcon "circle"
|
||||||
[ Svg.circle [ cx "12", cy "12", r "10" ] []
|
[ Svg.circle [ cx "12", cy "12", r "10" ] []
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
slash : Html msg
|
slash : Html msg
|
||||||
slash =
|
slash =
|
||||||
svgFeatherIcon "slash"
|
svgFeatherIcon "slash"
|
||||||
@ -105,18 +127,21 @@ slash =
|
|||||||
, Svg.line [ x1 "4.93", y1 "4.93", x2 "19.07", y2 "19.07" ] []
|
, Svg.line [ x1 "4.93", y1 "4.93", x2 "19.07", y2 "19.07" ] []
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
triangle : Html msg
|
triangle : Html msg
|
||||||
triangle =
|
triangle =
|
||||||
svgFeatherIcon "triangle"
|
svgFeatherIcon "triangle"
|
||||||
[ Svg.path [ d "M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" ] []
|
[ Svg.path [ d "M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" ] []
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
square : Html msg
|
square : Html msg
|
||||||
square =
|
square =
|
||||||
svgFeatherIcon "square"
|
svgFeatherIcon "square"
|
||||||
[ Svg.rect [ Svg.Attributes.x "3", y "3", width "18", height "18", rx "2", ry "2" ] []
|
[ Svg.rect [ Svg.Attributes.x "3", y "3", width "18", height "18", rx "2", ry "2" ] []
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
search : Html msg
|
search : Html msg
|
||||||
search =
|
search =
|
||||||
svgFeatherIcon "search"
|
svgFeatherIcon "search"
|
||||||
|
@ -20,12 +20,11 @@ import Html.Attributes as Attributes
|
|||||||
import Set exposing (Set)
|
import Set exposing (Set)
|
||||||
import Time
|
import Time
|
||||||
import Widget
|
import Widget
|
||||||
import Widget.FilterSelect as FilterSelect
|
|
||||||
import Widget.ScrollingNav as ScrollingNav
|
import Widget.ScrollingNav as ScrollingNav
|
||||||
import Widget.Snackbar as Snackbar
|
import Widget.Snackbar as Snackbar
|
||||||
import Widget.SortTable as SortTable
|
import Widget.SortTable as SortTable
|
||||||
import Widget.ValidatedInput as ValidatedInput
|
import Data.Style exposing (Style)
|
||||||
|
import Data.Theme as Theme exposing (Theme)
|
||||||
|
|
||||||
type alias Model =
|
type alias Model =
|
||||||
SortTable.Model
|
SortTable.Model
|
||||||
@ -54,36 +53,37 @@ init =
|
|||||||
SortTable.sortBy { title = "Name", asc = True }
|
SortTable.sortBy { title = "Name", asc = True }
|
||||||
|
|
||||||
|
|
||||||
snackbar : ((String,Bool) -> msg) -> (String,Element msg)
|
snackbar : Style msg -> (( String, Bool ) -> msg) -> ( String, Element msg,Element msg )
|
||||||
snackbar addSnackbar =
|
snackbar style addSnackbar =
|
||||||
( "Snackbar"
|
( "Snackbar"
|
||||||
, [Input.button Button.simple
|
, [ Widget.button style.button
|
||||||
{ onPress = Just <| addSnackbar <|
|
{ onPress =
|
||||||
("This is a notification. It will disappear after 10 seconds."
|
Just <|
|
||||||
|
addSnackbar <|
|
||||||
|
( "This is a notification. It will disappear after 10 seconds."
|
||||||
, False
|
, False
|
||||||
)
|
)
|
||||||
, label =
|
, text = "Add Notification"
|
||||||
"Add Notification"
|
, icon =Element.none
|
||||||
|> Element.text
|
|
||||||
|> List.singleton
|
|
||||||
|> Element.paragraph []
|
|
||||||
}
|
}
|
||||||
, Input.button Button.simple
|
, Widget.button style.button
|
||||||
{ onPress = Just <| addSnackbar <|
|
{ onPress =
|
||||||
("You can add another notification if you want."
|
Just <|
|
||||||
|
addSnackbar <|
|
||||||
|
( "You can add another notification if you want."
|
||||||
, True
|
, True
|
||||||
)
|
)
|
||||||
, label =
|
, text = "Add Notification with Action"
|
||||||
"Add Notification with Action"
|
, icon = Element.none
|
||||||
|> Element.text
|
|
||||||
|> List.singleton
|
|
||||||
|> Element.paragraph []
|
|
||||||
}
|
}
|
||||||
] |> Element.column Grid.simple
|
]
|
||||||
|
|> Element.column Grid.simple
|
||||||
|
, Element.none
|
||||||
)
|
)
|
||||||
|
|
||||||
sortTable : SortTable.Model -> (String,Element Msg)
|
|
||||||
sortTable model =
|
sortTable : Style Msg -> SortTable.Model -> ( String, Element Msg,Element Msg )
|
||||||
|
sortTable style model =
|
||||||
( "Sort Table"
|
( "Sort Table"
|
||||||
, SortTable.view
|
, SortTable.view
|
||||||
{ content =
|
{ content =
|
||||||
@ -152,31 +152,41 @@ sortTable model =
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|> Element.table Grid.simple
|
|> Element.table Grid.simple
|
||||||
|
, Element.none
|
||||||
)
|
)
|
||||||
|
|
||||||
scrollingNavCard : (String , Element msg )
|
|
||||||
scrollingNavCard =
|
scrollingNavCard : Style msg -> ( String, Element msg, Element msg )
|
||||||
("Scrolling Nav"
|
scrollingNavCard style =
|
||||||
|
( "Scrolling Nav"
|
||||||
, Element.text "Resize the screen and open the side-menu. Then start scrolling to see the scrolling navigation in action."
|
, Element.text "Resize the screen and open the side-menu. Then start scrolling to see the scrolling navigation in action."
|
||||||
|> List.singleton
|
|> List.singleton
|
||||||
|> Element.paragraph []
|
|> Element.paragraph []
|
||||||
|
, Element.none
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
view :
|
view :
|
||||||
{ addSnackbar : (String,Bool) -> msg
|
Theme ->
|
||||||
|
{ addSnackbar : ( String, Bool ) -> msg
|
||||||
, msgMapper : Msg -> msg
|
, msgMapper : Msg -> msg
|
||||||
, model : Model
|
, model : Model
|
||||||
}
|
}
|
||||||
-> { title : String
|
->
|
||||||
|
{ title : String
|
||||||
, description : String
|
, description : String
|
||||||
, items : List (String,Element msg)
|
, items : List ( String, Element msg,Element msg )
|
||||||
}
|
}
|
||||||
view { addSnackbar, msgMapper, model } =
|
view theme { addSnackbar, msgMapper, model } =
|
||||||
|
let
|
||||||
|
style = Theme.toStyle theme
|
||||||
|
in
|
||||||
{ title = "Reusable Views"
|
{ title = "Reusable Views"
|
||||||
, description = "Reusable views have an internal state but no update function. You will need to do some wiring, but nothing complicated."
|
, description = "Reusable views have an internal state but no update function. You will need to do some wiring, but nothing complicated."
|
||||||
, items =
|
, items =
|
||||||
[ snackbar addSnackbar
|
[ snackbar style addSnackbar
|
||||||
, sortTable model |> Tuple.mapSecond (Element.map msgMapper)
|
, sortTable style model |> \(a,b,c) ->
|
||||||
, scrollingNavCard
|
(a,b |> Element.map msgMapper,c |> Element.map msgMapper)
|
||||||
|
, scrollingNavCard style
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
module Stateless exposing (Model, Msg, init, update, view)
|
module Stateless exposing (Model, Msg, init, update, view)
|
||||||
|
|
||||||
import Array exposing (Array)
|
import Array exposing (Array)
|
||||||
|
import Data.Style exposing (Style)
|
||||||
import Element exposing (Element)
|
import Element exposing (Element)
|
||||||
import Element.Background as Background
|
import Element.Background as Background
|
||||||
import Element.Border as Border
|
import Element.Border as Border
|
||||||
|
import Element.Font as Font
|
||||||
import Element.Input as Input
|
import Element.Input as Input
|
||||||
import Framework.Button as Button
|
import Framework.Button as Button
|
||||||
import Framework.Card as Card
|
import Framework.Card as Card
|
||||||
@ -16,19 +18,18 @@ import Framework.Tag as Tag
|
|||||||
import Heroicons.Solid as Heroicons
|
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 Widget.Style exposing (ButtonStyle)
|
|
||||||
import Layout exposing (Part(..))
|
|
||||||
import Icons
|
import Icons
|
||||||
|
import Layout exposing (Part(..))
|
||||||
|
import Set exposing (Set)
|
||||||
import Widget
|
import Widget
|
||||||
import Element.Font as Font
|
import Widget.Style exposing (ButtonStyle)
|
||||||
import Data.Style exposing (style)
|
import Data.Theme as Theme exposing (Theme)
|
||||||
|
|
||||||
type alias Model =
|
type alias Model =
|
||||||
{ selected : Maybe Int
|
{ selected : Maybe Int
|
||||||
, multiSelected : Set Int
|
, multiSelected : Set Int
|
||||||
, chipTextInput : Set String
|
, chipTextInput : Set String
|
||||||
, isCollapsed : Bool
|
, isExpanded : Bool
|
||||||
, carousel : Int
|
, carousel : Int
|
||||||
, tab : Maybe Int
|
, tab : Maybe Int
|
||||||
, button : Bool
|
, button : Bool
|
||||||
@ -53,7 +54,7 @@ init =
|
|||||||
{ selected = Nothing
|
{ selected = Nothing
|
||||||
, multiSelected = Set.empty
|
, multiSelected = Set.empty
|
||||||
, chipTextInput = Set.empty
|
, chipTextInput = Set.empty
|
||||||
, isCollapsed = False
|
, isExpanded = False
|
||||||
, carousel = 0
|
, carousel = 0
|
||||||
, tab = Just 1
|
, tab = Just 1
|
||||||
, button = True
|
, button = True
|
||||||
@ -87,7 +88,7 @@ update msg model =
|
|||||||
|
|
||||||
ToggleCollapsable bool ->
|
ToggleCollapsable bool ->
|
||||||
( { model
|
( { model
|
||||||
| isCollapsed = bool
|
| isExpanded = bool
|
||||||
}
|
}
|
||||||
, Cmd.none
|
, Cmd.none
|
||||||
)
|
)
|
||||||
@ -95,11 +96,13 @@ update msg model =
|
|||||||
ToggleTextInputChip string ->
|
ToggleTextInputChip string ->
|
||||||
( { model
|
( { model
|
||||||
| chipTextInput =
|
| chipTextInput =
|
||||||
model.chipTextInput |>
|
model.chipTextInput
|
||||||
if model.chipTextInput |> Set.member string then
|
|> (if model.chipTextInput |> Set.member string then
|
||||||
Set.remove string
|
Set.remove string
|
||||||
|
|
||||||
else
|
else
|
||||||
Set.insert string
|
Set.insert string
|
||||||
|
)
|
||||||
}
|
}
|
||||||
, Cmd.none
|
, Cmd.none
|
||||||
)
|
)
|
||||||
@ -122,22 +125,24 @@ update msg model =
|
|||||||
( { model | button = bool }, Cmd.none )
|
( { model | button = bool }, Cmd.none )
|
||||||
|
|
||||||
SetTextInput string ->
|
SetTextInput string ->
|
||||||
( {model | textInput = string },Cmd.none)
|
( { model | textInput = string }, Cmd.none )
|
||||||
|
|
||||||
Idle ->
|
Idle ->
|
||||||
( model, Cmd.none)
|
( model, Cmd.none )
|
||||||
|
|
||||||
|
|
||||||
select : Model -> (String,Element Msg)
|
select : Style Msg -> Model -> ( String, Element Msg,Element Msg )
|
||||||
select model =
|
select style model =
|
||||||
let
|
let
|
||||||
buttonStyle = style.button
|
buttonStyle =
|
||||||
|
style.button
|
||||||
in
|
in
|
||||||
( "Select"
|
( "Select"
|
||||||
, { selected = model.selected
|
, { selected = model.selected
|
||||||
, options =
|
, options =
|
||||||
[ 1, 2, 42 ]
|
[ 1, 2, 42 ]
|
||||||
|> List.map (\int ->
|
|> List.map
|
||||||
|
(\int ->
|
||||||
{ text = String.fromInt int
|
{ text = String.fromInt int
|
||||||
, icon = Element.none
|
, icon = Element.none
|
||||||
}
|
}
|
||||||
@ -145,104 +150,74 @@ select model =
|
|||||||
, onSelect = ChangedSelected >> Just
|
, onSelect = ChangedSelected >> Just
|
||||||
}
|
}
|
||||||
|> Widget.select
|
|> Widget.select
|
||||||
|> List.indexedMap
|
|> Widget.buttonRow
|
||||||
(\i ->
|
{ list = style.row
|
||||||
Widget.selectButton
|
, button = style.button
|
||||||
{ buttonStyle
|
|
||||||
| container = buttonStyle.container
|
|
||||||
++ (if i == 0 then
|
|
||||||
Group.left
|
|
||||||
|
|
||||||
else if i == 2 then
|
|
||||||
Group.right
|
|
||||||
|
|
||||||
else
|
|
||||||
Group.center
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
)
|
, Element.none
|
||||||
|
|
||||||
|> Element.row Grid.compact
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
multiSelect : Model -> (String,Element Msg)
|
multiSelect : Style Msg -> Model -> ( String, Element Msg, Element Msg )
|
||||||
multiSelect model =
|
multiSelect style model =
|
||||||
let
|
let
|
||||||
buttonStyle = style.button
|
buttonStyle =
|
||||||
|
style.button
|
||||||
in
|
in
|
||||||
( "Multi Select"
|
( "Multi Select"
|
||||||
, { selected = model.multiSelected
|
, { selected = model.multiSelected
|
||||||
, options =
|
, options =
|
||||||
[ 1, 2, 42 ]
|
[ 1, 2, 42 ]
|
||||||
|> List.map (\int ->
|
|> List.map
|
||||||
|
(\int ->
|
||||||
{ text = String.fromInt int
|
{ text = String.fromInt int
|
||||||
, icon = Element.none
|
, icon = Element.none
|
||||||
})
|
}
|
||||||
|
)
|
||||||
, onSelect = ChangedMultiSelected >> Just
|
, onSelect = ChangedMultiSelected >> Just
|
||||||
}
|
}
|
||||||
|> Widget.multiSelect
|
|> Widget.multiSelect
|
||||||
|> List.indexedMap
|
|> Widget.buttonRow
|
||||||
(\i ->
|
{ list = style.row
|
||||||
Widget.selectButton
|
, button = style.button
|
||||||
{ buttonStyle
|
|
||||||
| container = buttonStyle.container
|
|
||||||
++ (if i == 0 then
|
|
||||||
Group.left
|
|
||||||
|
|
||||||
else if i == 2 then
|
|
||||||
Group.right
|
|
||||||
|
|
||||||
else
|
|
||||||
Group.center
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
)
|
, Element.none
|
||||||
|> Element.row Grid.compact
|
|
||||||
)
|
)
|
||||||
|
|
||||||
collapsable : Model -> (String,Element Msg)
|
expansionPanel : Style Msg -> Model -> (String,Element Msg,Element Msg)
|
||||||
collapsable model =
|
expansionPanel style model =
|
||||||
( "Collapsable"
|
( "Expansion Panel"
|
||||||
, { onToggle = ToggleCollapsable
|
, { onToggle = ToggleCollapsable
|
||||||
, isCollapsed = model.isCollapsed
|
, isExpanded = model.isExpanded
|
||||||
, label =
|
, icon = Element.none
|
||||||
Element.row (Grid.simple ++ [Element.width<| Element.fill])
|
, text = "Title"
|
||||||
[ if model.isCollapsed then
|
|
||||||
Icons.chevronRight |> Element.html |> Element.el []
|
|
||||||
|
|
||||||
else
|
|
||||||
Icons.chevronDown |> Element.html |> Element.el []
|
|
||||||
, Element.text <| "Title"
|
|
||||||
]
|
|
||||||
, content = Element.text <| "Hello World"
|
, content = Element.text <| "Hello World"
|
||||||
}
|
}
|
||||||
|>Widget.collapsable
|
|>Widget.expansionPanel style.expansionPanel
|
||||||
{ containerColumn = Card.simple ++ Grid.simple
|
, Element.none
|
||||||
++ [ Element.padding 8 ]
|
|
||||||
, button = []
|
|
||||||
}
|
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
tab : Model -> (String,Element Msg)
|
|
||||||
tab model =
|
|
||||||
|
|
||||||
|
tab : Style Msg -> Model -> ( String, Element Msg, Element Msg )
|
||||||
|
tab style model =
|
||||||
( "Tab"
|
( "Tab"
|
||||||
, Widget.tab
|
, Widget.tab style.tab
|
||||||
{ button = style.tabButton
|
{ tabs =
|
||||||
, optionRow = Grid.simple
|
|
||||||
, containerColumn = Grid.compact
|
|
||||||
}
|
|
||||||
{ selected = model.tab
|
{ selected = model.tab
|
||||||
, options = [ 1, 2, 3 ]
|
, options =
|
||||||
|> List.map (\int ->
|
[ 1, 2, 3 ]
|
||||||
|
|> List.map
|
||||||
|
(\int ->
|
||||||
{ text = "Tab " ++ (int |> String.fromInt)
|
{ text = "Tab " ++ (int |> String.fromInt)
|
||||||
, icon = Element.none
|
, icon = Element.none
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
, onSelect = ChangedTab >> Just
|
, onSelect = ChangedTab >> Just
|
||||||
} <|
|
}
|
||||||
(\selected ->
|
, content =
|
||||||
|
\selected ->
|
||||||
(case selected of
|
(case selected of
|
||||||
Just 0 ->
|
Just 0 ->
|
||||||
"This is Tab 1"
|
"This is Tab 1"
|
||||||
@ -257,51 +232,63 @@ tab model =
|
|||||||
"Please select a tab"
|
"Please select a tab"
|
||||||
)
|
)
|
||||||
|> Element.text
|
|> Element.text
|
||||||
|> Element.el (Card.small ++ Group.bottom)
|
}
|
||||||
)
|
, Element.none
|
||||||
)
|
)
|
||||||
|
|
||||||
modal : (Maybe Part -> msg) -> Model -> (String,Element msg)
|
|
||||||
modal changedSheet model =
|
modal : Style msg -> (Maybe Part -> msg) -> Model -> ( String, Element msg,Element msg )
|
||||||
|
modal style changedSheet model =
|
||||||
( "Modal"
|
( "Modal"
|
||||||
, [ Input.button Button.simple
|
, [ Widget.button style.button
|
||||||
{ onPress = Just <| changedSheet <| Just LeftSheet
|
{ onPress = Just <| changedSheet <| Just LeftSheet
|
||||||
, label = Element.text <| "show left sheet"
|
, text = "show left sheet"
|
||||||
|
, icon = Element.none
|
||||||
}
|
}
|
||||||
, Input.button Button.simple
|
, Widget.button style.button
|
||||||
{ onPress = Just <| changedSheet <| Just RightSheet
|
{ onPress = Just <| changedSheet <| Just RightSheet
|
||||||
, label = Element.text <| "show right sheet"
|
, text = "show right sheet"
|
||||||
|
, icon = Element.none
|
||||||
}
|
}
|
||||||
] |> Element.column Grid.simple
|
]
|
||||||
|
|> Element.column Grid.simple
|
||||||
|
,Element.none
|
||||||
)
|
)
|
||||||
|
|
||||||
dialog : msg -> Model -> (String,Element msg)
|
|
||||||
dialog showDialog model =
|
dialog : Style msg -> msg -> Model -> ( String, Element msg, Element msg )
|
||||||
|
dialog style showDialog model =
|
||||||
( "Dialog"
|
( "Dialog"
|
||||||
, Input.button Button.simple
|
, Widget.button style.button
|
||||||
{ onPress = Just showDialog
|
{ onPress = Just showDialog
|
||||||
, label = Element.text <| "Show dialog"
|
, text = "Show dialog"
|
||||||
|
, icon = Element.none
|
||||||
}
|
}
|
||||||
|
, Element.none
|
||||||
)
|
)
|
||||||
|
|
||||||
carousel : Model -> (String,Element Msg)
|
|
||||||
carousel model =
|
carousel : Style Msg -> Model -> ( String, Element Msg, Element Msg )
|
||||||
|
carousel style model =
|
||||||
( "Carousel"
|
( "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 =
|
, label =
|
||||||
\c ->
|
\c ->
|
||||||
[ Element.el [Element.centerY] <|
|
[ Element.el [ Element.centerY ] <|
|
||||||
Widget.iconButton style.button
|
Widget.iconButton style.button
|
||||||
{ onPress =
|
{ onPress =
|
||||||
model.carousel - 1
|
model.carousel
|
||||||
|> \i ->
|
- 1
|
||||||
|
|> (\i ->
|
||||||
if i < 0 then
|
if i < 0 then
|
||||||
Nothing
|
Nothing
|
||||||
|
|
||||||
else
|
else
|
||||||
SetCarousel i
|
SetCarousel i
|
||||||
|> Just
|
|> Just
|
||||||
|
)
|
||||||
, icon =
|
, icon =
|
||||||
Icons.chevronLeft
|
Icons.chevronLeft
|
||||||
|> Element.html
|
|> Element.html
|
||||||
@ -319,13 +306,17 @@ carousel model =
|
|||||||
Element.none
|
Element.none
|
||||||
, Element.el [ Element.centerY ] <|
|
, Element.el [ Element.centerY ] <|
|
||||||
Widget.iconButton style.button
|
Widget.iconButton style.button
|
||||||
{ onPress = model.carousel + 1
|
{ onPress =
|
||||||
|> \i ->
|
model.carousel
|
||||||
|
+ 1
|
||||||
|
|> (\i ->
|
||||||
if i >= 4 then
|
if i >= 4 then
|
||||||
Nothing
|
Nothing
|
||||||
|
|
||||||
else
|
else
|
||||||
SetCarousel i
|
SetCarousel i
|
||||||
|> Just
|
|> Just
|
||||||
|
)
|
||||||
, icon =
|
, icon =
|
||||||
Icons.chevronRight
|
Icons.chevronRight
|
||||||
|> Element.html
|
|> Element.html
|
||||||
@ -335,16 +326,20 @@ carousel model =
|
|||||||
]
|
]
|
||||||
|> Element.row (Grid.simple ++ [ Element.centerX, Element.width <| Element.shrink ])
|
|> Element.row (Grid.simple ++ [ Element.centerX, Element.width <| Element.shrink ])
|
||||||
}
|
}
|
||||||
|
, Element.none
|
||||||
)
|
)
|
||||||
|
|
||||||
iconButton : Model -> (String,Element Msg)
|
|
||||||
iconButton model =
|
iconButton : Style Msg -> Model -> ( String, Element Msg, Element Msg )
|
||||||
|
iconButton style model =
|
||||||
( "Icon Button"
|
( "Icon Button"
|
||||||
, [ [ Widget.button style.primaryButton
|
, [ Widget.button style.primaryButton
|
||||||
{ text = "disable me"
|
{ text = "disable me"
|
||||||
, icon = Icons.slash |> Element.html |> Element.el [] , onPress =
|
, icon = Icons.slash |> Element.html |> Element.el []
|
||||||
|
, onPress =
|
||||||
if model.button then
|
if model.button then
|
||||||
Just <| ToggleButton False
|
Just <| ToggleButton False
|
||||||
|
|
||||||
else
|
else
|
||||||
Nothing
|
Nothing
|
||||||
}
|
}
|
||||||
@ -355,21 +350,54 @@ iconButton model =
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|> Element.row Grid.simple
|
|> Element.row Grid.simple
|
||||||
|
, Element.column Grid.simple
|
||||||
|
[ Element.row Grid.spacedEvenly
|
||||||
|
[ "Button"
|
||||||
|
|> Element.text
|
||||||
, Widget.button style.button
|
, Widget.button style.button
|
||||||
{ text = "reset button"
|
{ text = "reset"
|
||||||
, icon = Element.none
|
, icon = Icons.repeat |> Element.html |> Element.el []
|
||||||
, onPress = Just <| ToggleButton True
|
, onPress = Just <| ToggleButton True
|
||||||
}
|
}
|
||||||
] |> Element.column Grid.simple
|
]
|
||||||
|
, 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 : Model -> (String,Element Msg)
|
|
||||||
textInput model =
|
textInput : Style Msg -> Model -> ( String, Element Msg, Element Msg )
|
||||||
|
textInput style model =
|
||||||
( "Chip Text Input"
|
( "Chip Text Input"
|
||||||
, [ { chips =
|
, [ { chips =
|
||||||
model.chipTextInput
|
model.chipTextInput
|
||||||
|> Set.toList
|
|> Set.toList
|
||||||
|> List.map (\string ->
|
|> List.map
|
||||||
|
(\string ->
|
||||||
{ icon = Element.none
|
{ icon = Element.none
|
||||||
, text = string
|
, text = string
|
||||||
, onPress =
|
, onPress =
|
||||||
@ -386,45 +414,61 @@ textInput model =
|
|||||||
|> Widget.textInput style.textInput
|
|> Widget.textInput style.textInput
|
||||||
, model.chipTextInput
|
, model.chipTextInput
|
||||||
|> Set.diff
|
|> Set.diff
|
||||||
(["A","B","C"]
|
([ "A", "B", "C" ]
|
||||||
|> Set.fromList
|
|> Set.fromList
|
||||||
)
|
)
|
||||||
|> Set.toList
|
|> Set.toList
|
||||||
|> List.map
|
|> List.map
|
||||||
(\string ->
|
(\string ->
|
||||||
Input.button (Button.simple ++ Tag.simple)
|
Widget.button style.textInput.chipButton
|
||||||
{ onPress =
|
{ onPress =
|
||||||
string
|
string
|
||||||
|> ToggleTextInputChip
|
|> ToggleTextInputChip
|
||||||
|> Just
|
|> Just
|
||||||
, label = Element.text string
|
, text = string
|
||||||
|
, icon = Element.none
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|> Element.wrappedRow [ Element.spacing 10 ]
|
|> Element.wrappedRow [ Element.spacing 10 ]
|
||||||
] |> Element.column Grid.simple
|
]
|
||||||
|
|> Element.column Grid.simple
|
||||||
|
, Element.none
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
view :
|
view :
|
||||||
|
Theme ->
|
||||||
{ msgMapper : Msg -> msg
|
{ msgMapper : Msg -> msg
|
||||||
, showDialog : msg
|
, showDialog : msg
|
||||||
, changedSheet : Maybe Part -> msg
|
, changedSheet : Maybe Part -> msg
|
||||||
} -> Model
|
|
||||||
-> { title : String
|
|
||||||
, description : String
|
|
||||||
, items : List (String,Element msg)
|
|
||||||
}
|
}
|
||||||
view { msgMapper, showDialog, changedSheet } model =
|
-> Model
|
||||||
|
->
|
||||||
|
{ title : String
|
||||||
|
, description : String
|
||||||
|
, items : List ( String, Element msg, Element msg )
|
||||||
|
}
|
||||||
|
view theme { msgMapper, showDialog, changedSheet } model =
|
||||||
|
let
|
||||||
|
style = Theme.toStyle theme
|
||||||
|
|
||||||
|
map (a,b,c) =
|
||||||
|
( a
|
||||||
|
, b |> Element.map msgMapper
|
||||||
|
, c |> Element.map msgMapper
|
||||||
|
)
|
||||||
|
in
|
||||||
{ title = "Stateless Views"
|
{ title = "Stateless Views"
|
||||||
, description = "Stateless views are simple functions that view some content. No wiring required."
|
, description = "Stateless views are simple functions that view some content. No wiring required."
|
||||||
, items =
|
, items =
|
||||||
[ iconButton model |> Tuple.mapSecond (Element.map msgMapper)
|
[ iconButton style model |> map
|
||||||
, select model |> Tuple.mapSecond (Element.map msgMapper)
|
, select style model |> map
|
||||||
, multiSelect model |> Tuple.mapSecond (Element.map msgMapper)
|
, multiSelect style model |> map
|
||||||
, collapsable model |> Tuple.mapSecond (Element.map msgMapper)
|
, expansionPanel style model |> map
|
||||||
, modal changedSheet model
|
, modal style changedSheet model
|
||||||
, carousel model |> Tuple.mapSecond (Element.map msgMapper)
|
, carousel style model |> map
|
||||||
, tab model |> Tuple.mapSecond (Element.map msgMapper)
|
, tab style model |> map
|
||||||
, dialog showDialog model
|
, dialog style showDialog model
|
||||||
, textInput model |> Tuple.mapSecond (Element.map msgMapper)
|
, textInput style model |> map
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -14,8 +14,8 @@ import Widget.Style exposing (ButtonStyle)
|
|||||||
|
|
||||||
type alias Button msg =
|
type alias Button msg =
|
||||||
{ text : String
|
{ text : String
|
||||||
, icon : Element Never
|
|
||||||
, onPress : Maybe msg
|
, onPress : Maybe msg
|
||||||
|
, icon : Element Never
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ iconButton style { onPress, text, icon } =
|
|||||||
Input.button
|
Input.button
|
||||||
(style.container
|
(style.container
|
||||||
++ (if onPress == Nothing then
|
++ (if onPress == Nothing then
|
||||||
style.disabled
|
style.ifDisabled
|
||||||
|
|
||||||
else
|
else
|
||||||
[]
|
[]
|
||||||
@ -60,7 +60,7 @@ button style { onPress, text, icon } =
|
|||||||
Input.button
|
Input.button
|
||||||
(style.container
|
(style.container
|
||||||
++ (if onPress == Nothing then
|
++ (if onPress == Nothing then
|
||||||
style.disabled
|
style.ifDisabled
|
||||||
|
|
||||||
else
|
else
|
||||||
[]
|
[]
|
||||||
@ -68,7 +68,7 @@ button style { onPress, text, icon } =
|
|||||||
)
|
)
|
||||||
{ onPress = onPress
|
{ onPress = onPress
|
||||||
, label =
|
, label =
|
||||||
Element.row style.label
|
Element.row style.labelRow
|
||||||
[ icon |> Element.map never
|
[ icon |> Element.map never
|
||||||
, Element.text text
|
, Element.text text
|
||||||
]
|
]
|
||||||
|
@ -51,10 +51,10 @@ dialog style { title, body, accept, dismiss } =
|
|||||||
Nothing
|
Nothing
|
||||||
, content =
|
, content =
|
||||||
Element.column
|
Element.column
|
||||||
(style.containerColumn
|
([ Element.centerX
|
||||||
++ [ Element.centerX
|
|
||||||
, Element.centerY
|
, Element.centerY
|
||||||
]
|
]
|
||||||
|
++ style.containerColumn
|
||||||
)
|
)
|
||||||
[ title
|
[ title
|
||||||
|> Maybe.map
|
|> Maybe.map
|
||||||
@ -64,22 +64,22 @@ dialog style { title, body, accept, dismiss } =
|
|||||||
|> Maybe.withDefault Element.none
|
|> Maybe.withDefault Element.none
|
||||||
, body
|
, body
|
||||||
, Element.row
|
, Element.row
|
||||||
(style.buttonRow
|
([ Element.alignRight
|
||||||
++ [ Element.alignRight
|
|
||||||
, Element.width <| Element.shrink
|
, Element.width <| Element.shrink
|
||||||
]
|
]
|
||||||
|
++ style.buttonRow
|
||||||
)
|
)
|
||||||
(case ( accept, dismiss ) of
|
(case ( accept, dismiss ) of
|
||||||
( Just acceptButton, Nothing ) ->
|
( Just acceptButton, Nothing ) ->
|
||||||
acceptButton
|
acceptButton
|
||||||
|> Button.textButton style.accept
|
|> Button.textButton style.acceptButton
|
||||||
|> List.singleton
|
|> List.singleton
|
||||||
|
|
||||||
( Just acceptButton, Just dismissButton ) ->
|
( Just acceptButton, Just dismissButton ) ->
|
||||||
[ dismissButton
|
[ dismissButton
|
||||||
|> Button.textButton style.dismiss
|
|> Button.textButton style.dismissButton
|
||||||
, acceptButton
|
, acceptButton
|
||||||
|> Button.textButton style.accept
|
|> Button.textButton style.acceptButton
|
||||||
]
|
]
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
|
46
src/Internal/ExpansionPanel.elm
Normal file
46
src/Internal/ExpansionPanel.elm
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
module Internal.ExpansionPanel exposing (ExpansionPanel, expansionPanel)
|
||||||
|
|
||||||
|
{-| Part of Material Design Lists
|
||||||
|
-}
|
||||||
|
|
||||||
|
import Element exposing (Element)
|
||||||
|
import Element.Events as Events
|
||||||
|
import Widget.Style exposing (ExpansionPanelStyle)
|
||||||
|
|
||||||
|
|
||||||
|
type alias ExpansionPanel msg =
|
||||||
|
{ onToggle : Bool -> msg
|
||||||
|
, icon : Element Never
|
||||||
|
, text : String
|
||||||
|
, content : Element msg
|
||||||
|
, isExpanded : Bool
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
expansionPanel :
|
||||||
|
ExpansionPanelStyle msg
|
||||||
|
-> ExpansionPanel msg
|
||||||
|
-> Element msg
|
||||||
|
expansionPanel style model =
|
||||||
|
Element.column style.containerColumn <|
|
||||||
|
[ Element.row
|
||||||
|
((Events.onClick <| model.onToggle <| not model.isExpanded)
|
||||||
|
:: style.panelRow
|
||||||
|
)
|
||||||
|
[ Element.row style.labelRow
|
||||||
|
[ model.icon |> Element.map never
|
||||||
|
, model.text |> Element.text
|
||||||
|
]
|
||||||
|
, Element.map never <|
|
||||||
|
if model.isExpanded then
|
||||||
|
style.collapseIcon
|
||||||
|
|
||||||
|
else
|
||||||
|
style.expandIcon
|
||||||
|
]
|
||||||
|
, if model.isExpanded then
|
||||||
|
Element.el style.content <| model.content
|
||||||
|
|
||||||
|
else
|
||||||
|
Element.none
|
||||||
|
]
|
108
src/Internal/List.elm
Normal file
108
src/Internal/List.elm
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
module Internal.List exposing (buttonColumn, buttonRow, column, row)
|
||||||
|
|
||||||
|
import Element exposing (Attribute, Element)
|
||||||
|
import Internal.Button exposing (Button)
|
||||||
|
import Internal.Select as Select
|
||||||
|
import Widget.Style exposing (ButtonStyle, ColumnStyle, RowStyle)
|
||||||
|
|
||||||
|
|
||||||
|
internal :
|
||||||
|
{ list
|
||||||
|
| element : List (Attribute msg)
|
||||||
|
, ifFirst : List (Attribute msg)
|
||||||
|
, ifLast : List (Attribute msg)
|
||||||
|
, ifCenter : List (Attribute msg)
|
||||||
|
}
|
||||||
|
-> List (Element msg)
|
||||||
|
-> List (Element msg)
|
||||||
|
internal style list =
|
||||||
|
list
|
||||||
|
|> List.indexedMap
|
||||||
|
(\i ->
|
||||||
|
Element.el <|
|
||||||
|
style.element
|
||||||
|
++ (if List.length list == 1 then
|
||||||
|
[]
|
||||||
|
|
||||||
|
else if i == 0 then
|
||||||
|
style.ifFirst
|
||||||
|
|
||||||
|
else if i == (List.length list - 1) then
|
||||||
|
style.ifLast
|
||||||
|
|
||||||
|
else
|
||||||
|
style.ifCenter
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
row : RowStyle msg -> List (Element msg) -> Element msg
|
||||||
|
row style =
|
||||||
|
internal style >> Element.row style.containerRow
|
||||||
|
|
||||||
|
|
||||||
|
column : ColumnStyle msg -> List (Element msg) -> Element msg
|
||||||
|
column style =
|
||||||
|
internal style >> Element.column style.containerColumn
|
||||||
|
|
||||||
|
|
||||||
|
internalButton :
|
||||||
|
{ list :
|
||||||
|
{ list
|
||||||
|
| element : List (Attribute msg)
|
||||||
|
, ifFirst : List (Attribute msg)
|
||||||
|
, ifLast : List (Attribute msg)
|
||||||
|
, ifCenter : List (Attribute msg)
|
||||||
|
}
|
||||||
|
, button : ButtonStyle msg
|
||||||
|
}
|
||||||
|
-> List ( Bool, Button msg )
|
||||||
|
-> List (Element msg)
|
||||||
|
internalButton style list =
|
||||||
|
list
|
||||||
|
|> List.indexedMap
|
||||||
|
(\i ->
|
||||||
|
Select.selectButton
|
||||||
|
{ container =
|
||||||
|
style.button.container
|
||||||
|
++ style.list.element
|
||||||
|
++ (if List.length list == 1 then
|
||||||
|
[]
|
||||||
|
|
||||||
|
else if i == 0 then
|
||||||
|
style.list.ifFirst
|
||||||
|
|
||||||
|
else if i == (List.length list - 1) then
|
||||||
|
style.list.ifLast
|
||||||
|
|
||||||
|
else
|
||||||
|
style.list.ifCenter
|
||||||
|
)
|
||||||
|
, labelRow =
|
||||||
|
style.button.labelRow
|
||||||
|
, ifDisabled =
|
||||||
|
style.button.ifDisabled
|
||||||
|
, ifActive =
|
||||||
|
style.button.ifActive
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
buttonRow :
|
||||||
|
{ list : RowStyle msg
|
||||||
|
, button : ButtonStyle msg
|
||||||
|
}
|
||||||
|
-> List ( Bool, Button msg )
|
||||||
|
-> Element msg
|
||||||
|
buttonRow style =
|
||||||
|
internalButton style >> Element.row style.list.containerRow
|
||||||
|
|
||||||
|
|
||||||
|
buttonColumn :
|
||||||
|
{ list : ColumnStyle msg
|
||||||
|
, button : ButtonStyle msg
|
||||||
|
}
|
||||||
|
-> List ( Bool, Button msg )
|
||||||
|
-> Element msg
|
||||||
|
buttonColumn style =
|
||||||
|
internalButton style >> Element.column style.list.containerColumn
|
@ -1,4 +1,4 @@
|
|||||||
module Internal.Select exposing (multiSelect, select, selectButton)
|
module Internal.Select exposing (MultiSelect, Select, multiSelect, select, selectButton)
|
||||||
|
|
||||||
import Element exposing (Element)
|
import Element exposing (Element)
|
||||||
import Internal.Button as Button exposing (Button)
|
import Internal.Button as Button exposing (Button)
|
||||||
@ -39,7 +39,7 @@ selectButton style ( selected, b ) =
|
|||||||
| container =
|
| container =
|
||||||
style.container
|
style.container
|
||||||
++ (if selected then
|
++ (if selected then
|
||||||
style.active
|
style.ifActive
|
||||||
|
|
||||||
else
|
else
|
||||||
[]
|
[]
|
||||||
|
24
src/Internal/Tab.elm
Normal file
24
src/Internal/Tab.elm
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
module Internal.Tab exposing (Tab, tab)
|
||||||
|
|
||||||
|
import Element exposing (Element)
|
||||||
|
import Internal.Select as Select exposing (Select)
|
||||||
|
import Widget.Style exposing (TabStyle)
|
||||||
|
|
||||||
|
|
||||||
|
type alias Tab msg =
|
||||||
|
{ tabs : Select msg
|
||||||
|
, content : Maybe Int -> Element msg
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
tab : TabStyle msg -> Tab msg -> Element msg
|
||||||
|
tab style { tabs, content } =
|
||||||
|
[ tabs
|
||||||
|
|> Select.select
|
||||||
|
|> List.map (Select.selectButton style.button)
|
||||||
|
|> Element.row style.optionRow
|
||||||
|
, tabs.selected
|
||||||
|
|> content
|
||||||
|
|> Element.el style.content
|
||||||
|
]
|
||||||
|
|> Element.column style.containerColumn
|
34
src/Internal/TextInput.elm
Normal file
34
src/Internal/TextInput.elm
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
module Internal.TextInput exposing (TextInput, textInput)
|
||||||
|
|
||||||
|
import Element exposing (Element)
|
||||||
|
import Element.Input as Input exposing (Placeholder)
|
||||||
|
import Internal.Button as Button exposing (Button)
|
||||||
|
import Widget.Style exposing (TextInputStyle)
|
||||||
|
|
||||||
|
|
||||||
|
type alias TextInput msg =
|
||||||
|
{ chips : List (Button msg)
|
||||||
|
, text : String
|
||||||
|
, placeholder : Maybe (Placeholder msg)
|
||||||
|
, label : String
|
||||||
|
, onChange : String -> msg
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
textInput : TextInputStyle msg -> TextInput msg -> Element msg
|
||||||
|
textInput style { chips, placeholder, label, text, onChange } =
|
||||||
|
Element.row style.containerRow
|
||||||
|
[ if chips |> List.isEmpty then
|
||||||
|
Element.none
|
||||||
|
|
||||||
|
else
|
||||||
|
chips
|
||||||
|
|> List.map (Button.button style.chipButton)
|
||||||
|
|> Element.row style.chipsRow
|
||||||
|
, Input.text style.input
|
||||||
|
{ onChange = onChange
|
||||||
|
, text = text
|
||||||
|
, placeholder = placeholder
|
||||||
|
, label = Input.labelHidden label
|
||||||
|
}
|
||||||
|
]
|
149
src/Widget.elm
149
src/Widget.elm
@ -2,7 +2,9 @@ module Widget exposing
|
|||||||
( Button, TextButton, iconButton, textButton, button
|
( Button, TextButton, iconButton, textButton, button
|
||||||
, Select, MultiSelect, selectButton, select, multiSelect
|
, Select, MultiSelect, selectButton, select, multiSelect
|
||||||
, Dialog, modal, dialog
|
, Dialog, modal, dialog
|
||||||
, TextInputStyle, textInput, collapsable, carousel, tab
|
, ExpansionPanel, expansionPanel
|
||||||
|
, TextInputStyle, textInput, carousel, tab
|
||||||
|
, Tab, buttonColumn, buttonRow, column, row
|
||||||
)
|
)
|
||||||
|
|
||||||
{-| This module contains functions for displaying data.
|
{-| This module contains functions for displaying data.
|
||||||
@ -23,20 +25,28 @@ module Widget exposing
|
|||||||
@docs Dialog, modal, dialog
|
@docs Dialog, modal, dialog
|
||||||
|
|
||||||
|
|
||||||
|
# ExpansionPanel
|
||||||
|
|
||||||
|
@docs ExpansionPanel, expansionPanel
|
||||||
|
|
||||||
|
|
||||||
# Other Widgets
|
# Other Widgets
|
||||||
|
|
||||||
@docs TextInputStyle, textInput, collapsable, carousel, tab
|
@docs TextInputStyle, textInput, carousel, tab
|
||||||
|
|
||||||
-}
|
-}
|
||||||
|
|
||||||
import Array exposing (Array)
|
import Array exposing (Array)
|
||||||
import Element exposing (Attribute, Element)
|
import Element exposing (Attribute, Element)
|
||||||
import Element.Input as Input exposing (Placeholder)
|
import Element.Input exposing (Placeholder)
|
||||||
import Internal.Button as Button
|
import Internal.Button as Button
|
||||||
import Internal.Dialog as Dialog
|
import Internal.Dialog as Dialog
|
||||||
|
import Internal.ExpansionPanel as ExpansionPanel
|
||||||
|
import Internal.List as List
|
||||||
import Internal.Select as Select
|
import Internal.Select as Select
|
||||||
|
import Internal.TextInput as TextInput
|
||||||
import Set exposing (Set)
|
import Set exposing (Set)
|
||||||
import Widget.Style exposing (ButtonStyle, DialogStyle)
|
import Widget.Style exposing (ButtonStyle, ColumnStyle, DialogStyle, ExpansionPanelStyle, RowStyle, TabStyle)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -216,13 +226,44 @@ dialog =
|
|||||||
|
|
||||||
|
|
||||||
{----------------------------------------------------------
|
{----------------------------------------------------------
|
||||||
- OTHER STATELESS WIDGETS
|
- DIALOG
|
||||||
|
----------------------------------------------------------}
|
||||||
|
|
||||||
|
|
||||||
|
type alias ExpansionPanel msg =
|
||||||
|
{ onToggle : Bool -> msg
|
||||||
|
, icon : Element Never
|
||||||
|
, text : String
|
||||||
|
, expandIcon : Element Never
|
||||||
|
, collapseIcon : Element Never
|
||||||
|
, content : Element msg
|
||||||
|
, isExpanded : Bool
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
expansionPanel :
|
||||||
|
ExpansionPanelStyle msg
|
||||||
|
->
|
||||||
|
{ onToggle : Bool -> msg
|
||||||
|
, icon : Element Never
|
||||||
|
, text : String
|
||||||
|
, content : Element msg
|
||||||
|
, isExpanded : Bool
|
||||||
|
}
|
||||||
|
-> Element msg
|
||||||
|
expansionPanel =
|
||||||
|
ExpansionPanel.expansionPanel
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{----------------------------------------------------------
|
||||||
|
- TEXT INPUT
|
||||||
----------------------------------------------------------}
|
----------------------------------------------------------}
|
||||||
|
|
||||||
|
|
||||||
{-| -}
|
{-| -}
|
||||||
type alias TextInputStyle msg =
|
type alias TextInputStyle msg =
|
||||||
{ chip : ButtonStyle msg
|
{ chipButton : ButtonStyle msg
|
||||||
, containerRow : List (Attribute msg)
|
, containerRow : List (Attribute msg)
|
||||||
, chipsRow : List (Attribute msg)
|
, chipsRow : List (Attribute msg)
|
||||||
, input : List (Attribute msg)
|
, input : List (Attribute msg)
|
||||||
@ -240,65 +281,75 @@ textInput :
|
|||||||
, onChange : String -> msg
|
, onChange : String -> msg
|
||||||
}
|
}
|
||||||
-> Element msg
|
-> Element msg
|
||||||
textInput style { chips, placeholder, label, text, onChange } =
|
textInput =
|
||||||
Element.row style.containerRow
|
TextInput.textInput
|
||||||
[ chips
|
|
||||||
|> List.map (Button.button style.chip)
|
|
||||||
|> Element.row style.chipsRow
|
|
||||||
, Input.text style.input
|
|
||||||
{ onChange = onChange
|
|
||||||
, text = text
|
|
||||||
, placeholder = placeholder
|
|
||||||
, label = Input.labelHidden label
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
{-| Some collapsable content.
|
|
||||||
-}
|
{----------------------------------------------------------
|
||||||
collapsable :
|
- LIST
|
||||||
{ containerColumn : List (Attribute msg)
|
----------------------------------------------------------}
|
||||||
, button : List (Attribute msg)
|
|
||||||
}
|
|
||||||
->
|
row : RowStyle msg -> List (Element msg) -> Element msg
|
||||||
{ onToggle : Bool -> msg
|
row =
|
||||||
, isCollapsed : Bool
|
List.row
|
||||||
, label : Element msg
|
|
||||||
, content : Element msg
|
|
||||||
|
column : ColumnStyle msg -> List (Element msg) -> Element msg
|
||||||
|
column =
|
||||||
|
List.column
|
||||||
|
|
||||||
|
|
||||||
|
buttonRow :
|
||||||
|
{ list : RowStyle msg
|
||||||
|
, button : ButtonStyle msg
|
||||||
}
|
}
|
||||||
|
-> List ( Bool, Button msg )
|
||||||
-> Element msg
|
-> Element msg
|
||||||
collapsable style { onToggle, isCollapsed, label, content } =
|
buttonRow =
|
||||||
Element.column style.containerColumn <|
|
List.buttonRow
|
||||||
[ Input.button style.button
|
|
||||||
{ onPress = Just <| onToggle <| not isCollapsed
|
|
||||||
, label = label
|
|
||||||
}
|
|
||||||
]
|
|
||||||
++ (if isCollapsed then
|
|
||||||
[]
|
|
||||||
|
|
||||||
else
|
|
||||||
[ content ]
|
buttonColumn :
|
||||||
)
|
{ list : ColumnStyle msg
|
||||||
|
, button : ButtonStyle msg
|
||||||
|
}
|
||||||
|
-> List ( Bool, Button msg )
|
||||||
|
-> Element msg
|
||||||
|
buttonColumn =
|
||||||
|
List.buttonColumn
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{----------------------------------------------------------
|
||||||
|
- OTHER STATELESS WIDGETS
|
||||||
|
----------------------------------------------------------}
|
||||||
|
|
||||||
|
|
||||||
|
type alias Tab msg =
|
||||||
|
{ tabs : Select msg
|
||||||
|
, content : Maybe Int -> Element msg
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
{-| Displayes a list of contents in a tab
|
{-| Displayes a list of contents in a tab
|
||||||
-}
|
-}
|
||||||
tab :
|
tab :
|
||||||
{ button : ButtonStyle msg
|
TabStyle msg
|
||||||
, optionRow : List (Attribute msg)
|
->
|
||||||
, containerColumn : List (Attribute msg)
|
{ tabs : Select msg
|
||||||
|
, content : Maybe Int -> Element msg
|
||||||
}
|
}
|
||||||
-> Select msg
|
|
||||||
-> (Maybe Int -> Element msg)
|
|
||||||
-> Element msg
|
-> Element msg
|
||||||
tab style options content =
|
tab style { tabs, content } =
|
||||||
[ options
|
[ tabs
|
||||||
|> select
|
|> select
|
||||||
|> List.map (selectButton style.button)
|
|> List.map (selectButton style.button)
|
||||||
|> Element.row style.optionRow
|
|> Element.row style.optionRow
|
||||||
, options.selected
|
, tabs.selected
|
||||||
|> content
|
|> content
|
||||||
|
|> Element.el style.content
|
||||||
]
|
]
|
||||||
|> Element.column style.containerColumn
|
|> Element.column style.containerColumn
|
||||||
|
|
||||||
|
@ -1,108 +0,0 @@
|
|||||||
module Widget.FilterMultiSelect exposing (Model, Msg(..), init, update, viewInput, viewOptions)
|
|
||||||
|
|
||||||
{-|
|
|
||||||
|
|
||||||
@docs Model, Msg, init, update, viewInput, viewOptions
|
|
||||||
|
|
||||||
-}
|
|
||||||
|
|
||||||
import Element.Input exposing (Placeholder)
|
|
||||||
import Set exposing (Set)
|
|
||||||
import Widget exposing (Button)
|
|
||||||
|
|
||||||
|
|
||||||
{-| The Model containing the raw value, the selected value and all the possible options.
|
|
||||||
-}
|
|
||||||
type alias Model =
|
|
||||||
{ raw : String
|
|
||||||
, selected : Set String
|
|
||||||
, options : Set String
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
{-| The Msg is exposed by design. You can unselect by sending `Selected Nothing`.
|
|
||||||
-}
|
|
||||||
type Msg
|
|
||||||
= ChangedRaw String
|
|
||||||
| ToggleSelected String
|
|
||||||
|
|
||||||
|
|
||||||
{-| The initial state contains the set of possible options.
|
|
||||||
-}
|
|
||||||
init : Set String -> Model
|
|
||||||
init options =
|
|
||||||
{ raw = ""
|
|
||||||
, selected = Set.empty
|
|
||||||
, options = options
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
{-| Updates the Model
|
|
||||||
-}
|
|
||||||
update : Msg -> Model -> Model
|
|
||||||
update msg model =
|
|
||||||
case msg of
|
|
||||||
ChangedRaw string ->
|
|
||||||
{ model
|
|
||||||
| raw = string
|
|
||||||
}
|
|
||||||
|
|
||||||
ToggleSelected string ->
|
|
||||||
if model.selected |> Set.member string then
|
|
||||||
{ model
|
|
||||||
| selected = model.selected |> Set.remove string
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{ model
|
|
||||||
| selected = model.selected |> Set.insert string
|
|
||||||
, raw = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
{-| A wrapper around Input.text.
|
|
||||||
-}
|
|
||||||
viewInput :
|
|
||||||
Model
|
|
||||||
->
|
|
||||||
{ msgMapper : Msg -> msg
|
|
||||||
, placeholder : Maybe (Placeholder msg)
|
|
||||||
, label : String
|
|
||||||
, toChip : String -> Button msg
|
|
||||||
}
|
|
||||||
->
|
|
||||||
{ chips : List (Button msg)
|
|
||||||
, text : String
|
|
||||||
, placeholder : Maybe (Placeholder msg)
|
|
||||||
, label : String
|
|
||||||
, onChange : String -> msg
|
|
||||||
}
|
|
||||||
viewInput model { msgMapper, placeholder, label, toChip } =
|
|
||||||
{ chips =
|
|
||||||
model.selected
|
|
||||||
|> Set.toList
|
|
||||||
|> List.map toChip
|
|
||||||
, text = model.raw
|
|
||||||
, placeholder = placeholder
|
|
||||||
, label = label
|
|
||||||
, onChange = ChangedRaw >> msgMapper
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
{-| Returns a List of all options that matches the filter.
|
|
||||||
-}
|
|
||||||
viewOptions : Model -> List String
|
|
||||||
viewOptions { raw, options, selected } =
|
|
||||||
if raw == "" then
|
|
||||||
[]
|
|
||||||
|
|
||||||
else
|
|
||||||
options
|
|
||||||
|> Set.filter (String.toUpper >> String.contains (raw |> String.toUpper))
|
|
||||||
|> Set.filter
|
|
||||||
(\string ->
|
|
||||||
selected
|
|
||||||
|> Set.member string
|
|
||||||
|> not
|
|
||||||
)
|
|
||||||
|> Set.toList
|
|
@ -1,93 +0,0 @@
|
|||||||
module Widget.FilterSelect exposing (Model, Msg(..), init, update, viewInput, viewOptions)
|
|
||||||
|
|
||||||
{-|
|
|
||||||
|
|
||||||
@docs Model, Msg, init, update, viewInput, viewOptions
|
|
||||||
|
|
||||||
-}
|
|
||||||
|
|
||||||
import Element exposing (Attribute, Element)
|
|
||||||
import Element.Input as Input exposing (Placeholder)
|
|
||||||
import Set exposing (Set)
|
|
||||||
|
|
||||||
|
|
||||||
{-| The Model containing the raw value, the selected value and all the possible options.
|
|
||||||
-}
|
|
||||||
type alias Model =
|
|
||||||
{ raw : String
|
|
||||||
, selected : Maybe String
|
|
||||||
, options : Set String
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
{-| The Msg is exposed by design. You can unselect by sending `Selected Nothing`.
|
|
||||||
-}
|
|
||||||
type Msg
|
|
||||||
= ChangedRaw String
|
|
||||||
| Selected (Maybe String)
|
|
||||||
|
|
||||||
|
|
||||||
{-| The initial state contains the set of possible options.
|
|
||||||
-}
|
|
||||||
init : Set String -> Model
|
|
||||||
init options =
|
|
||||||
{ raw = ""
|
|
||||||
, selected = Nothing
|
|
||||||
, options = options
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
{-| Updates the Model
|
|
||||||
-}
|
|
||||||
update : Msg -> Model -> Model
|
|
||||||
update msg model =
|
|
||||||
case msg of
|
|
||||||
ChangedRaw string ->
|
|
||||||
{ model
|
|
||||||
| raw = string
|
|
||||||
}
|
|
||||||
|
|
||||||
Selected maybe ->
|
|
||||||
{ model
|
|
||||||
| selected = maybe
|
|
||||||
}
|
|
||||||
|> (case maybe of
|
|
||||||
Just string ->
|
|
||||||
\m -> { m | raw = string }
|
|
||||||
|
|
||||||
Nothing ->
|
|
||||||
identity
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
{-| A wrapper around Input.text.
|
|
||||||
-}
|
|
||||||
viewInput :
|
|
||||||
List (Attribute msg)
|
|
||||||
-> Model
|
|
||||||
->
|
|
||||||
{ msgMapper : Msg -> msg
|
|
||||||
, placeholder : Maybe (Placeholder msg)
|
|
||||||
, label : String
|
|
||||||
}
|
|
||||||
-> Element msg
|
|
||||||
viewInput attributes model { msgMapper, placeholder, label } =
|
|
||||||
Input.text attributes
|
|
||||||
{ onChange = ChangedRaw >> msgMapper
|
|
||||||
, text = model.raw
|
|
||||||
, placeholder = placeholder
|
|
||||||
, label = Input.labelHidden label
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
{-| Returns a List of all options that matches the filter.
|
|
||||||
-}
|
|
||||||
viewOptions : Model -> List String
|
|
||||||
viewOptions { raw, options } =
|
|
||||||
if raw == "" then
|
|
||||||
[]
|
|
||||||
|
|
||||||
else
|
|
||||||
options
|
|
||||||
|> Set.filter (String.toUpper >> String.contains (raw |> String.toUpper))
|
|
||||||
|> Set.toList
|
|
@ -18,10 +18,10 @@ module Widget.Snackbar exposing
|
|||||||
|
|
||||||
-}
|
-}
|
||||||
|
|
||||||
import Element exposing (Attribute, Element)
|
import Element exposing (Element)
|
||||||
import Queue exposing (Queue)
|
import Queue exposing (Queue)
|
||||||
import Widget exposing (TextButton)
|
import Widget exposing (TextButton)
|
||||||
import Widget.Style exposing (ButtonStyle)
|
import Widget.Style exposing (SnackbarStyle)
|
||||||
|
|
||||||
|
|
||||||
type alias Message msg =
|
type alias Message msg =
|
||||||
@ -105,10 +105,7 @@ current model =
|
|||||||
|
|
||||||
|
|
||||||
view :
|
view :
|
||||||
{ row : List (Attribute msg)
|
SnackbarStyle msg
|
||||||
, text : List (Attribute msg)
|
|
||||||
, button : ButtonStyle msg
|
|
||||||
}
|
|
||||||
-> (a -> Message msg)
|
-> (a -> Message msg)
|
||||||
-> Model a
|
-> Model a
|
||||||
-> Maybe (Element msg)
|
-> Maybe (Element msg)
|
||||||
@ -127,6 +124,6 @@ view style toMessage model =
|
|||||||
(Widget.textButton style.button)
|
(Widget.textButton style.button)
|
||||||
|> Maybe.withDefault Element.none
|
|> Maybe.withDefault Element.none
|
||||||
]
|
]
|
||||||
|> Element.row style.row
|
|> Element.row style.containerRow
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
module Widget.Style exposing (ButtonStyle, DialogStyle, Style)
|
module Widget.Style exposing (ButtonStyle, ColumnStyle, DialogStyle, ExpansionPanelStyle, RowStyle, SnackbarStyle, Style, TabStyle, TextInputStyle)
|
||||||
|
|
||||||
import Element exposing (Attribute, Element)
|
import Element exposing (Attribute, Element)
|
||||||
import Html exposing (Html)
|
import Html exposing (Html)
|
||||||
@ -6,9 +6,9 @@ import Html exposing (Html)
|
|||||||
|
|
||||||
type alias ButtonStyle msg =
|
type alias ButtonStyle msg =
|
||||||
{ container : List (Attribute msg)
|
{ container : List (Attribute msg)
|
||||||
, disabled : List (Attribute msg)
|
, labelRow : List (Attribute msg)
|
||||||
, label : List (Attribute msg)
|
, ifDisabled : List (Attribute msg)
|
||||||
, active : List (Attribute msg)
|
, ifActive : List (Attribute msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -16,18 +16,65 @@ type alias DialogStyle msg =
|
|||||||
{ containerColumn : List (Attribute msg)
|
{ containerColumn : List (Attribute msg)
|
||||||
, title : List (Attribute msg)
|
, title : List (Attribute msg)
|
||||||
, buttonRow : List (Attribute msg)
|
, buttonRow : List (Attribute msg)
|
||||||
, accept : ButtonStyle msg
|
, acceptButton : ButtonStyle msg
|
||||||
, dismiss : ButtonStyle msg
|
, dismissButton : ButtonStyle msg
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type alias ExpansionPanelStyle msg =
|
||||||
|
{ containerColumn : List (Attribute msg)
|
||||||
|
, panelRow : List (Attribute msg)
|
||||||
|
, labelRow : List (Attribute msg)
|
||||||
|
, content : List (Attribute msg)
|
||||||
|
, expandIcon : Element Never
|
||||||
|
, collapseIcon : Element Never
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type alias SnackbarStyle msg =
|
||||||
|
{ containerRow : List (Attribute msg)
|
||||||
|
, text : List (Attribute msg)
|
||||||
|
, button : ButtonStyle msg
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type alias TextInputStyle msg =
|
||||||
|
{ chipButton : ButtonStyle msg
|
||||||
|
, containerRow : List (Attribute msg)
|
||||||
|
, chipsRow : List (Attribute msg)
|
||||||
|
, input : List (Attribute msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type alias TabStyle msg =
|
||||||
|
{ button : ButtonStyle msg
|
||||||
|
, optionRow : List (Attribute msg)
|
||||||
|
, containerColumn : List (Attribute msg)
|
||||||
|
, content : List (Attribute msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type alias RowStyle msg =
|
||||||
|
{ containerRow : List (Attribute msg)
|
||||||
|
, element : List (Attribute msg)
|
||||||
|
, ifFirst : List (Attribute msg)
|
||||||
|
, ifLast : List (Attribute msg)
|
||||||
|
, ifCenter : List (Attribute msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type alias ColumnStyle msg =
|
||||||
|
{ containerColumn : List (Attribute msg)
|
||||||
|
, element : List (Attribute msg)
|
||||||
|
, ifFirst : List (Attribute msg)
|
||||||
|
, ifLast : List (Attribute msg)
|
||||||
|
, ifCenter : List (Attribute msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type alias Style style msg =
|
type alias Style style msg =
|
||||||
{ style
|
{ style
|
||||||
| snackbar :
|
| snackbar : SnackbarStyle msg
|
||||||
{ row : List (Attribute msg)
|
|
||||||
, text : List (Attribute msg)
|
|
||||||
, button : ButtonStyle msg
|
|
||||||
}
|
|
||||||
, layout : List (Attribute msg) -> Element msg -> Html msg
|
, layout : List (Attribute msg) -> Element msg -> Html msg
|
||||||
, header : List (Attribute msg)
|
, header : List (Attribute msg)
|
||||||
, sheet : List (Attribute msg)
|
, sheet : List (Attribute msg)
|
||||||
|
@ -1,161 +0,0 @@
|
|||||||
module Widget.ValidatedInput exposing
|
|
||||||
( Model, Msg, init, update, view
|
|
||||||
, getError, getRaw, getValue
|
|
||||||
)
|
|
||||||
|
|
||||||
{-| The validated Input is a wrapper around `Input.text`.
|
|
||||||
They can validate the input and return an error if nessarry.
|
|
||||||
|
|
||||||
|
|
||||||
# Basics
|
|
||||||
|
|
||||||
@docs Model, Msg, init, update, view
|
|
||||||
|
|
||||||
|
|
||||||
# Access the Model
|
|
||||||
|
|
||||||
@docs getError, getRaw, getValue
|
|
||||||
|
|
||||||
-}
|
|
||||||
|
|
||||||
import Element exposing (Attribute, Element)
|
|
||||||
import Element.Events as Events
|
|
||||||
import Element.Input as Input exposing (Placeholder)
|
|
||||||
|
|
||||||
|
|
||||||
{-| -}
|
|
||||||
type Model err a
|
|
||||||
= Model
|
|
||||||
{ raw : Maybe String
|
|
||||||
, value : a
|
|
||||||
, err : Maybe err
|
|
||||||
, validator : String -> Result err a
|
|
||||||
, toString : a -> String
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
{-| returns the raw value (the value that the user currently sees)
|
|
||||||
-}
|
|
||||||
getRaw : Model err a -> String
|
|
||||||
getRaw (Model { raw, value, toString }) =
|
|
||||||
case raw of
|
|
||||||
Just string ->
|
|
||||||
string
|
|
||||||
|
|
||||||
Nothing ->
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
{-| -}
|
|
||||||
type Msg
|
|
||||||
= ChangedRaw String
|
|
||||||
| LostFocus
|
|
||||||
| 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
|
|
||||||
{ raw = Nothing
|
|
||||||
, value = value
|
|
||||||
, err = Nothing
|
|
||||||
, validator = validator
|
|
||||||
, toString = toString
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
{-| -}
|
|
||||||
update : Msg -> Model err a -> Model err a
|
|
||||||
update msg (Model model) =
|
|
||||||
case msg of
|
|
||||||
StartEditing ->
|
|
||||||
Model
|
|
||||||
{ model
|
|
||||||
| raw = model.value |> model.toString |> Just
|
|
||||||
}
|
|
||||||
|
|
||||||
ChangedRaw string ->
|
|
||||||
Model
|
|
||||||
{ model
|
|
||||||
| raw = Just string
|
|
||||||
, err = Nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
LostFocus ->
|
|
||||||
case model.raw of
|
|
||||||
Just string ->
|
|
||||||
case model.validator string of
|
|
||||||
Ok value ->
|
|
||||||
Model
|
|
||||||
{ model
|
|
||||||
| value = value
|
|
||||||
, raw = Nothing
|
|
||||||
, err = Nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
Err err ->
|
|
||||||
Model
|
|
||||||
{ model
|
|
||||||
| raw = Nothing
|
|
||||||
, err = Just err
|
|
||||||
}
|
|
||||||
|
|
||||||
Nothing ->
|
|
||||||
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
|
|
||||||
->
|
|
||||||
{ msgMapper : Msg -> msg
|
|
||||||
, placeholder : Maybe (Placeholder msg)
|
|
||||||
, label : String
|
|
||||||
, readOnly : a -> Element msg
|
|
||||||
}
|
|
||||||
-> Element msg
|
|
||||||
view attributes (Model model) { msgMapper, placeholder, label, readOnly } =
|
|
||||||
case model.raw of
|
|
||||||
Just string ->
|
|
||||||
Input.text (attributes ++ [ Events.onLoseFocus <| msgMapper <| LostFocus ])
|
|
||||||
{ onChange = ChangedRaw >> msgMapper
|
|
||||||
, text = string
|
|
||||||
, placeholder = placeholder
|
|
||||||
, label = Input.labelHidden label
|
|
||||||
}
|
|
||||||
|
|
||||||
Nothing ->
|
|
||||||
Input.button []
|
|
||||||
{ onPress = Just (StartEditing |> msgMapper)
|
|
||||||
, label = model.value |> readOnly
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user