Started with Material Design

This commit is contained in:
Unknown 2020-05-17 22:02:29 +02:00
parent bc2c86257f
commit 308a049613
28 changed files with 1843 additions and 926 deletions

View File

@ -5,12 +5,10 @@
"license": "BSD-3-Clause",
"version": "1.0.0",
"exposed-modules": [
"Widget",
"Widget.FilterSelect",
"Widget.ValidatedInput",
"Widget.Layout",
"Widget.Style",
"Widget.ScrollingNav",
"Widget.Snackbar",
"Widget.SortTable"
"Widget.Snackbar"
],
"elm-version": "0.19.0 <= v < 0.20.0",
"dependencies": {
@ -29,4 +27,4 @@
"test-dependencies": {
"elm-explorations/test": "1.2.1 <= v < 2.0.0"
}
}
}

View File

@ -8,6 +8,7 @@
"dependencies": {
"direct": {
"Orasund/elm-ui-framework": "1.6.1",
"avh4/elm-color": "1.0.0",
"elm/browser": "1.0.2",
"elm/core": "1.0.5",
"elm/html": "1.0.0",
@ -17,14 +18,17 @@
"feathericons/elm-feather": "1.4.0",
"jasonliang512/elm-heroicons": "1.0.2",
"mdgriffith/elm-ui": "1.1.5",
"noahzgordon/elm-color-extra": "1.0.2",
"ryannhg/elm-spa": "4.1.0",
"turboMaCk/queue": "1.0.2",
"wernerdegroot/listzipper": "4.0.0"
},
"indirect": {
"elm/json": "1.1.3",
"elm/regex": "1.0.0",
"elm/url": "1.0.0",
"elm/virtual-dom": "1.0.2"
"elm/virtual-dom": "1.0.2",
"fredcy/elm-parseint": "2.0.1"
}
},
"test-dependencies": {

View File

@ -3,10 +3,15 @@ module Data.Example exposing (Model, Msg, init, subscriptions, toCardList, updat
import Data.Style exposing (Style)
import Element exposing (Element)
import Example.Button as Button
import Example.Dialog as Dialog
import Example.ExpansionPanel as ExpansionPanel
import Example.List as List
import Example.Modal as Modal
import Example.MultiSelect as MultiSelect
import Example.Select as Select
import Example.SortTable as SortTable
import Example.Tab as Tab
import Example.TextInput as TextInput
import Framework.Grid as Grid
import View.Test as Test
@ -17,6 +22,11 @@ type Msg
| MultiSelect MultiSelect.Msg
| ExpansionPanel ExpansionPanel.Msg
| Tab Tab.Msg
| SortTable SortTable.Msg
| Modal Modal.Msg
| Dialog Dialog.Msg
| TextInput TextInput.Msg
| List List.Msg
type alias Model =
@ -25,6 +35,34 @@ type alias Model =
, multiSelect : MultiSelect.Model
, expansionPanel : ExpansionPanel.Model
, tab : Tab.Model
, sortTable : SortTable.Model
, modal : Modal.Model
, dialog : Dialog.Model
, textInput : TextInput.Model
, list : List.Model
}
type alias UpgradeRecord model msg =
{ from : Model -> model
, to : Model -> model -> Model
, msgMapper : msg -> Msg
, updateFun : msg -> model -> ( model, Cmd msg )
, subscriptionsFun : model -> Sub msg
}
type alias UpgradeCollection =
{ button : UpgradeRecord Button.Model Button.Msg
, select : UpgradeRecord Select.Model Select.Msg
, multiSelect : UpgradeRecord MultiSelect.Model MultiSelect.Msg
, expansionPanel : UpgradeRecord ExpansionPanel.Model ExpansionPanel.Msg
, tab : UpgradeRecord Tab.Model Tab.Msg
, sortTable : UpgradeRecord SortTable.Model SortTable.Msg
, modal : UpgradeRecord Modal.Model Modal.Msg
, dialog : UpgradeRecord Dialog.Model Dialog.Msg
, textInput : UpgradeRecord TextInput.Model TextInput.Msg
, list : UpgradeRecord List.Model List.Msg
}
@ -45,63 +83,175 @@ init =
( tabModel, tabMsg ) =
Tab.init
( sortTableModel, sortTableMsg ) =
SortTable.init
( modalModel, modalMsg ) =
Modal.init
( dialogModel, dialogMsg ) =
Dialog.init
( textInputModel, textInputMsg ) =
TextInput.init
( listModel, listMsg ) =
List.init
in
( { button = buttonModel
, select = selectModel
, multiSelect = multiSelectModel
, expansionPanel = expansionPanelModel
, tab = tabModel
, sortTable = sortTableModel
, modal = modalModel
, dialog = dialogModel
, textInput = textInputModel
, list = listModel
}
, [ Cmd.map Button buttonMsg
, Cmd.map Select selectMsg
, Cmd.map MultiSelect multiSelectMsg
, Cmd.map ExpansionPanel expansionPanelMsg
, Cmd.map Tab tabMsg
, Cmd.map SortTable sortTableMsg
, Cmd.map Modal modalMsg
, Cmd.map Dialog dialogMsg
, Cmd.map TextInput textInputMsg
, Cmd.map List listMsg
]
|> Cmd.batch
)
upgradeRecord : UpgradeCollection
upgradeRecord =
{ button =
{ from = .button
, to = \model a -> { model | button = a }
, msgMapper = Button
, updateFun = Button.update
, subscriptionsFun = Button.subscriptions
}
, select =
{ from = .select
, to = \model a -> { model | select = a }
, msgMapper = Select
, updateFun = Select.update
, subscriptionsFun = Select.subscriptions
}
, multiSelect =
{ from = .multiSelect
, to = \model a -> { model | multiSelect = a }
, msgMapper = MultiSelect
, updateFun = MultiSelect.update
, subscriptionsFun = MultiSelect.subscriptions
}
, expansionPanel =
{ from = .expansionPanel
, to = \model a -> { model | expansionPanel = a }
, msgMapper = ExpansionPanel
, updateFun = ExpansionPanel.update
, subscriptionsFun = ExpansionPanel.subscriptions
}
, tab =
{ from = .tab
, to = \model a -> { model | tab = a }
, msgMapper = Tab
, updateFun = Tab.update
, subscriptionsFun = Tab.subscriptions
}
, sortTable =
{ from = .sortTable
, to = \model a -> { model | sortTable = a }
, msgMapper = SortTable
, updateFun = SortTable.update
, subscriptionsFun = SortTable.subscriptions
}
, modal =
{ from = .modal
, to = \model a -> { model | modal = a }
, msgMapper = Modal
, updateFun = Modal.update
, subscriptionsFun = Modal.subscriptions
}
, dialog =
{ from = .dialog
, to = \model a -> { model | dialog = a }
, msgMapper = Dialog
, updateFun = Dialog.update
, subscriptionsFun = Dialog.subscriptions
}
, textInput =
{ from = .textInput
, to = \model a -> { model | textInput = a }
, msgMapper = TextInput
, updateFun = TextInput.update
, subscriptionsFun = TextInput.subscriptions
}
, list =
{ from = .list
, to = \model a -> { model | list = a }
, msgMapper = List
, updateFun = List.update
, subscriptionsFun = List.subscriptions
}
}
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
Button buttonMsg ->
Button.update buttonMsg model.button
|> Tuple.mapBoth
(\a -> { model | button = a })
(Cmd.map Button)
(case msg of
Button m ->
updateField .button m
Select selectMsg ->
Select.update selectMsg model.select
|> Tuple.mapBoth
(\a -> { model | select = a })
(Cmd.map Select)
Select m ->
updateField .select m
MultiSelect multiSelectMsg ->
MultiSelect.update multiSelectMsg model.multiSelect
|> Tuple.mapBoth
(\a -> { model | multiSelect = a })
(Cmd.map MultiSelect)
MultiSelect m ->
updateField .multiSelect m
ExpansionPanel expansionPanelMsg ->
ExpansionPanel.update expansionPanelMsg model.expansionPanel
|> Tuple.mapBoth
(\a -> { model | expansionPanel = a })
(Cmd.map ExpansionPanel)
ExpansionPanel m ->
updateField .expansionPanel m
Tab tabMsg ->
Tab.update tabMsg model.tab
|> Tuple.mapBoth
(\a -> { model | tab = a })
(Cmd.map Tab)
Tab m ->
updateField .tab m
SortTable m ->
updateField .sortTable m
Modal m ->
updateField .modal m
Dialog m ->
updateField .dialog m
TextInput m ->
updateField .textInput m
List m ->
updateField .list m
)
model
subscriptions : Model -> Sub Msg
subscriptions model =
[ Button.subscriptions model.button |> Sub.map Button
, Select.subscriptions model.select |> Sub.map Select
, MultiSelect.subscriptions model.multiSelect |> Sub.map MultiSelect
, ExpansionPanel.subscriptions model.expansionPanel |> Sub.map ExpansionPanel
, Tab.subscriptions model.tab |> Sub.map Tab
let
subFun { from, msgMapper, subscriptionsFun } =
subscriptionsFun (from model) |> Sub.map msgMapper
in
[ upgradeRecord.button |> subFun
, upgradeRecord.select |> subFun
, upgradeRecord.multiSelect |> subFun
, upgradeRecord.expansionPanel |> subFun
, upgradeRecord.tab |> subFun
, upgradeRecord.sortTable |> subFun
, upgradeRecord.modal |> subFun
, upgradeRecord.dialog |> subFun
, upgradeRecord.textInput |> subFun
, upgradeRecord.list |> subFun
]
|> Sub.batch
@ -116,33 +266,33 @@ view :
, multiSelect : Element msg
, expansionPanel : Element msg
, tab : Element msg
, sortTable : Element msg
, modal : Element msg
, dialog : Element msg
, textInput : Element msg
, list : Element msg
}
view msgMapper style model =
{ button =
Button.view
(Button >> msgMapper)
style
model.button
Button.view (Button >> msgMapper) style (.button model)
, select =
Select.view
(Select >> msgMapper)
style
model.select
Select.view (Select >> msgMapper) style (.select model)
, multiSelect =
MultiSelect.view
(MultiSelect >> msgMapper)
style
model.multiSelect
MultiSelect.view (MultiSelect >> msgMapper) style (.multiSelect model)
, expansionPanel =
ExpansionPanel.view
(ExpansionPanel >> msgMapper)
style
model.expansionPanel
ExpansionPanel.view (ExpansionPanel >> msgMapper) style (.expansionPanel model)
, tab =
Tab.view
(Tab >> msgMapper)
style
model.tab
Tab.view (Tab >> msgMapper) style (.tab model)
, sortTable =
SortTable.view (SortTable >> msgMapper) style (.sortTable model)
, modal =
Modal.view (Modal >> msgMapper) style (.modal model)
, dialog =
Dialog.view (Dialog >> msgMapper) style (.dialog model)
, textInput =
TextInput.view (TextInput >> msgMapper) style (.textInput model)
, list =
List.view (List >> msgMapper) style (.list model)
}
@ -154,9 +304,9 @@ toCardList :
}
-> List ( String, Element msg, Element msg )
toCardList { idle, msgMapper, style, model } =
[ { title = "Icon Button"
[ { title = "Button"
, example = .button
, test = Test.iconButton
, test = Test.button
}
, { title = "Select"
, example = .select
@ -174,7 +324,28 @@ toCardList { idle, msgMapper, style, model } =
, example = .tab
, test = Test.tab
}
, { title = "Sort Table"
, example = .sortTable
, test = Test.sortTable
}
, { title = "Modal"
, example = .modal
, test = Test.modal
}
, { title = "Dialog"
, example = .dialog
, test = Test.dialog
}
, { title = "Text Input"
, example = .textInput
, test = Test.textInput
}
, { title = "List"
, example = .list
, test = Test.list
}
]
|> List.sortBy .title
|> List.map
(\{ title, example, test } ->
( title
@ -182,6 +353,39 @@ toCardList { idle, msgMapper, style, model } =
|> view msgMapper style
|> example
, test idle style
|> Element.column Grid.simple
|> List.map
(\( name, elem ) ->
Element.row Grid.spacedEvenly
[ name
|> Element.text
|> List.singleton
|> Element.wrappedRow [ Element.width <| Element.shrink ]
, elem
|> Element.el [ Element.width <| Element.shrink ]
]
)
|> Element.column
(Grid.simple
++ [ Element.width <| Element.fill ]
)
)
)
{-------------------------------------------------------------------------------
-------------------------------------------------------------------------------}
updateField :
(UpgradeCollection -> UpgradeRecord model msg)
-> msg
-> Model
-> ( Model, Cmd Msg )
updateField getter msg model =
let
{ from, to, msgMapper, updateFun } =
getter upgradeRecord
in
updateFun msg (from model)
|> Tuple.mapBoth (to model) (Cmd.map msgMapper)

View File

@ -1,8 +1,17 @@
module Data.Style exposing (Style)
import Element exposing (Attribute)
import Widget.Style exposing (ButtonStyle, DialogStyle, ExpansionPanelStyle,
SnackbarStyle ,RowStyle,ColumnStyle,TextInputStyle,TabStyle)
import Widget.Style
exposing
( ButtonStyle
, ColumnStyle
, DialogStyle
, ExpansionPanelStyle
, RowStyle
, SortTableStyle
, TabStyle
, TextInputStyle
)
type alias Style msg =
Widget.Style.Style
@ -16,5 +25,6 @@ type alias Style msg =
, row : RowStyle msg
, column : ColumnStyle msg
, cardColumn : ColumnStyle msg
, sortTable : SortTableStyle msg
}
msg
msg

View File

@ -1,9 +1,9 @@
module Data.Style.ElmUiFramework exposing (style)
import Element exposing (Attribute)
import Data.Style exposing (Style)
import Element
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
@ -11,12 +11,21 @@ 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)
import Widget.Style
exposing
( ButtonStyle
, ColumnStyle
, DialogStyle
, ExpansionPanelStyle
, RowStyle
, SnackbarStyle
, SortTableStyle
, TabStyle
, TextInputStyle
)
textButton : ButtonStyle msg
textButton =
@ -24,6 +33,7 @@ textButton =
, labelRow = Grid.simple
, ifDisabled = Color.disabled
, ifActive = Color.primary
, otherwise = []
}
@ -33,6 +43,7 @@ simpleButton =
, labelRow = Grid.simple
, ifDisabled = Color.disabled
, ifActive = Color.primary
, otherwise = []
}
@ -57,6 +68,7 @@ menuTabButton =
, labelRow = Grid.simple
, ifDisabled = Color.disabled
, ifActive = [ Border.color Color.turquoise ]
, otherwise = []
}
@ -66,6 +78,7 @@ menuButton =
, container = Button.simple ++ Group.center ++ Color.dark
, ifDisabled = Color.disabled
, ifActive = Color.primary
, otherwise = []
}
@ -79,6 +92,7 @@ sheetButton =
, labelRow = Grid.simple
, ifDisabled = Color.disabled
, ifActive = Color.primary
, otherwise = []
}
@ -88,6 +102,7 @@ buttonStyle =
, container = Button.simple
, ifDisabled = Color.disabled
, ifActive = Color.primary
, otherwise = []
}
@ -97,6 +112,7 @@ snackbarButton =
, container = Button.simple ++ Color.dark
, ifDisabled = Color.disabled
, ifActive = Color.primary
, otherwise = []
}
@ -106,8 +122,10 @@ tabButtonStyle =
, container = Button.simple ++ Group.top
, ifDisabled = Color.disabled
, ifActive = Color.primary
, otherwise = []
}
textInputStyle : TextInputStyle msg
textInputStyle =
{ chipButton = chipButtonStyle
@ -143,41 +161,43 @@ chipButtonStyle =
, ifDisabled = []
, labelRow = Grid.simple
, ifActive = Color.primary
, otherwise = []
}
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]
{ 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 []
, 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
}
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 =
@ -186,19 +206,21 @@ snackbar =
++ Color.dark
++ Grid.simple
++ [ Element.paddingXY 8 6
, Element.height <| Element.px <| 54
]
, 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)
}
, optionRow = Grid.simple
, containerColumn = Grid.compact
, content = Card.small ++ Group.bottom
}
row : RowStyle msg
row =
@ -206,30 +228,44 @@ row =
, element = []
, ifFirst = Group.left
, ifLast = Group.right
, ifCenter = Group.center
, otherwise = Group.center
}
cardColumn : ColumnStyle msg
cardColumn =
{ containerColumn = Grid.compact ++ [Element.height <| Element.fill]
, element = Card.large ++ [Element.height <| Element.fill]
{ containerColumn = Grid.compact ++ [ Element.height <| Element.fill ]
, element = Card.large ++ [ Element.height <| Element.fill ]
, ifFirst = Group.top
, ifLast = Group.bottom
, ifCenter = Group.center
, otherwise = Group.center
}
column : ColumnStyle msg
column =
{ containerColumn = Grid.compact
, element = []
, ifFirst = Group.top
, ifLast = Group.bottom
, ifCenter =Group.center
, otherwise = Group.center
}
sortTable : SortTableStyle msg
sortTable =
{ containerTable = Grid.simple
, headerButton = tabButtonStyle
, ascIcon = Icons.chevronUp |> Element.html |> Element.el []
, descIcon = Icons.chevronDown |> Element.html |> Element.el []
, defaultIcon = Element.none
}
style : Style msg
style =
{ row = row
{ sortTable = sortTable
, row = row
, cardColumn = cardColumn
, column = column
, button = buttonStyle

View File

@ -0,0 +1,393 @@
module Data.Style.Material exposing (Palette, defaultPalette, style)
import Color exposing (Color)
import Color.Accessibility as Accessibility
import Color.Convert as Convert
import Color.Manipulate as Manipulate
import Data.Style exposing (Style)
import Element exposing (Attribute, Element)
import Element.Background as Background
import Element.Border as Border
import Element.Font as Font
import Html.Attributes as Attributes
import Widget.Style
exposing
( ButtonStyle
, ColumnStyle
, DialogStyle
, ExpansionPanelStyle
, RowStyle
, SnackbarStyle
, SortTableStyle
, TabStyle
, TextInputStyle
)
type alias Palette =
{ primary : Color --Color.rgb255 0x62 0x00 0xEE
, secondary : Color --Color.rgb255 0x03 0xda 0xc6
, background : Color --Color.rgb255 0xFF 0xFF 0xFF
, surface : Color --Color.rgb255 0xFF 0xFF 0xFF
, error : Color --Color.rgb255 0xB0 0x00 0x20
, on :
{ primary : Color --Color.rgb255 0xFF 0xFF 0xFF
, secondary : Color --Color.rgb255 0x00 0x00 0x00
, background : Color --Color.rgb255 0x00 0x00 0x00
, surface : Color --Color.rgb255 0x00 0x00 0x00
, error : Color --Color.rgb255 0xFF 0xFF 0xFF
}
}
defaultPalette : Palette
defaultPalette =
{ primary = Color.rgb255 0x62 0x00 0xEE
, secondary = Color.rgb255 0x03 0xDA 0xC6
, background = Color.rgb255 0xFF 0xFF 0xFF
, surface = Color.rgb255 0xFF 0xFF 0xFF
, error = Color.rgb255 0xB0 0x00 0x20
, on =
{ primary = Color.rgb255 0xFF 0xFF 0xFF
, secondary = Color.rgb255 0x00 0x00 0x00
, background = Color.rgb255 0x00 0x00 0x00
, surface = Color.rgb255 0x00 0x00 0x00
, error = Color.rgb255 0xFF 0xFF 0xFF
}
}
accessibleTextColor : Color -> Color
accessibleTextColor color =
if (0.05 / (Accessibility.luminance color + 0.05)) < 7 then
Color.rgb 255 255 255
else
Color.rgb 0 0 0
{-| using noahzgordon/elm-color-extra for colors
-}
withShade : Color -> Float -> Color -> Color
withShade c2 amount c1 =
let
alpha = c1
|> Color.toRgba |> .alpha
toCIELCH =
Convert.colorToLab
>> (\{ l, a, b } ->
{ l = l
, c = sqrt (a * a + b * b)
, h = atan2 b a
}
)
fromCIELCH =
(\{ l, c, h } ->
{ l = l
, a = c * cos h
, b = c * sin h
}
)
>> Convert.labToColor
fun a b =
{ l = (a.l * (1 - amount) + b.l * amount) / 1
, c = (a.c * (1 - amount) + b.c * amount) / 1
, h = (a.h * (1 - amount) + b.h * amount) / 1
}
in
fun (toCIELCH c1) (toCIELCH c2)
|> fromCIELCH
|> Color.toRgba
|> (\color -> { color | alpha = alpha })
|> Color.fromRgba
scaleOpacity : Float -> Color -> Color
scaleOpacity opacity =
Color.toRgba
>> (\color -> { color | alpha = color.alpha * opacity})
>> Color.fromRgba
{-| hsl 265 100 47 (0% onColor)
rgb 98 0 238
-}
primaryColor : Palette -> Color
primaryColor { primary } =
primary
{-| hsl 265 75 59 (24% onColor)
rgb 136 61 242
-}
primaryColorFocused : Palette -> Color
primaryColorFocused {primary, on } =
primary |> withShade on.primary 0.24
--Color.rgb255 0x87 0x3D 0xF2
{-| hsl 265 92 51 (08% onColor)
-}
primaryColorHover : Palette -> Color
primaryColorHover {primary, on } =
primary |> withShade on.primary 0.08
--Color.rgb255 0x6E 0x14 0xEF
{-| hsl 265 66 64 (32% onColor)
-}
primaryColorPressed : Palette -> Color
primaryColorPressed {primary, on } =
primary |> withShade on.primary 0.32
--Color.rgb255 0x94 0x52 0xF3
primaryColorDisabled : Palette ->Color
primaryColorDisabled {primary,on}=
Color.rgb255 0x77 0x77 0x77 |> scaleOpacity 0.38
disabledFontColor : Color
disabledFontColor =
Color.rgb255 0x77 0x77 0x77--0x85 0x85 0x85
shadow :
Float
->
{ offset : ( Float, Float )
, size : Float
, blur : Float
, color : Element.Color
}
shadow float =
{ color = Element.rgba255 0x00 0x00 0x00 0.2
, offset = ( 0, float )
, size = 0
, blur = float
}
primaryButton : Palette -> ButtonStyle msg
primaryButton palette =
{ container =
[ Element.height <| Element.px 36
, Element.width <| Element.minimum 64 <| Element.shrink
, Border.rounded <| 4
, Border.shadow <| shadow 2
, Font.size 14
, Font.medium
, Font.letterSpacing 1.25
, Element.htmlAttribute <| Attributes.style "text-transform" "uppercase"
, Element.paddingXY 16 8
, Element.mouseDown
[ Background.color <| Element.fromRgb <| Color.toRgba <| primaryColorPressed palette
, Font.color <| Element.fromRgb <| Color.toRgba <| accessibleTextColor <| primaryColorPressed palette
, Border.shadow <| shadow 12
]
, Element.mouseOver
[ Background.color <| Element.fromRgb <| Color.toRgba <| primaryColorHover palette
, Font.color <| Element.fromRgb <| Color.toRgba <| accessibleTextColor <| primaryColorHover palette
, Border.shadow <| shadow 6
]
, Element.focused
[ Background.color <| Element.fromRgb <| Color.toRgba <| primaryColorFocused palette
, Font.color <| Element.fromRgb <| Color.toRgba <| accessibleTextColor <| primaryColorFocused palette
, Border.shadow <| shadow 6
]
]
, labelRow =
[ Element.spacing <| 8
]
, ifDisabled =
[ Background.color <| Element.fromRgb <| Color.toRgba <| primaryColorDisabled palette
, Font.color <| Element.fromRgb <| Color.toRgba <| disabledFontColor
, Element.htmlAttribute <| Attributes.style "cursor" "not-allowed"
, Element.mouseDown []
, Element.mouseOver []
, Element.focused []
, Border.shadow <| shadow 0
]
, ifActive =
[ Background.color <| Element.fromRgb <| Color.toRgba <| primaryColorFocused palette
, Font.color <| Element.fromRgb <| Color.toRgba <| accessibleTextColor <| primaryColorHover palette
]
, otherwise =
[ Background.color <| Element.fromRgb <| Color.toRgba <| primaryColor palette
, Font.color <| Element.fromRgb <| Color.toRgba <| accessibleTextColor <| primaryColor palette
]
}
{-------------------------------------------------------------------------------
- Template
-------------------------------------------------------------------------------}
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"
, otherwise = box <| string ++ ":otherwise"
}
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"
, otherwise = box <| string ++ ":otherwise"
}
column : String -> ColumnStyle msg
column string =
{ containerColumn = box <| string ++ ":containerColumn"
, element = box <| string ++ ":element"
, ifFirst = box <| string ++ ":ifFirst"
, ifLast = box <| string ++ ":ifLast"
, otherwise = box <| string ++ ":otherwise"
}
sortTable : String -> SortTableStyle msg
sortTable string =
{ containerTable = box <| string ++ ":containerTable"
, headerButton = button <| string ++ ":headerButton"
, ascIcon = icon <| string ++ ":ascIcon"
, descIcon = icon <| string ++ ":descIcon"
, defaultIcon = icon <| string ++ ":defaultIcon"
}
style : Palette -> Style msg
style palette =
{ sortTable = sortTable <| "sortTable"
, row = row <| "row"
, cardColumn = column <| "cardRow"
, column = column <| "column"
, button = button <| "button"
, primaryButton = primaryButton palette
, 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"
}

View File

@ -1,16 +1,28 @@
module Data.Style.Template exposing (style)
import Data.Style exposing (Style)
import Element exposing (Attribute,Element)
import Element exposing (Attribute, Element)
import Element.Background as Background
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)
import Widget.Style
exposing
( ButtonStyle
, ColumnStyle
, DialogStyle
, ExpansionPanelStyle
, RowStyle
, SnackbarStyle
, TabStyle
, TextInputStyle
,SortTableStyle
)
fontSize : Int
fontSize = 10
fontSize =
10
box : String -> List (Attribute msg)
box string =
@ -18,15 +30,16 @@ box string =
, 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
, 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.below <|
Element.el [ Font.size <| fontSize ] <|
Element.text string
, Background.color <| Element.rgb 0.66 0.66 0.66
]
@ -35,15 +48,16 @@ decoration string =
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
]
|> 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 =
@ -51,8 +65,10 @@ button string =
, labelRow = box <| string ++ ":labelRow"
, ifDisabled = decoration <| string ++ ":ifDisabled"
, ifActive = decoration <| string ++ ":ifActive"
, otherwise = decoration <| string ++ ":otherwise"
}
snackbar : String -> SnackbarStyle msg
snackbar string =
{ containerRow = box <| string ++ ":containerRow"
@ -60,15 +76,17 @@ snackbar string =
, 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"
, dismissButton = button <| string ++ ":dismissButton"
}
expansionPanel : String -> ExpansionPanelStyle msg
expansionPanel string =
{ containerColumn = box <| string ++ ":containerColumn"
@ -79,6 +97,7 @@ expansionPanel string =
, collapseIcon = icon <| string ++ ":collapseIcon"
}
textInput : String -> TextInputStyle msg
textInput string =
{ chipButton = button <| string ++ ":chipButton"
@ -87,6 +106,7 @@ textInput string =
, input = box <| string ++ ":input"
}
tab : String -> TabStyle msg
tab string =
{ button = button <| string ++ ":button"
@ -95,27 +115,41 @@ tab string =
, 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"
, otherwise = box <| string ++ ":otherwise"
}
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"
, otherwise = box <| string ++ ":otherwise"
}
style :Style msg
sortTable : String -> SortTableStyle msg
sortTable string =
{ containerTable = box <| string ++ ":containerTable"
, headerButton = button <| string ++ ":headerButton"
, ascIcon = icon <| string ++ ":ascIcon"
, descIcon = icon <| string ++ ":descIcon"
, defaultIcon = icon <| string ++ ":defaultIcon"
}
style : Style msg
style =
{ row = row <| "row"
{ sortTable = sortTable <| "sortTable"
, row = row <| "row"
, cardColumn = column <| "cardRow"
, column = column <| "column"
, button = button <| "button"
@ -139,4 +173,4 @@ style =
, searchIcon = icon "searchIcon"
, search = box "search"
, searchFill = box "searchFill"
}
}

View File

@ -1,17 +1,25 @@
module Data.Theme exposing (Theme(..),toStyle)
module Data.Theme exposing (Theme(..), toStyle)
import Data.Style exposing (Style)
import Data.Style.ElmUiFramework
import Data.Style.Material
import Data.Style.Template
type Theme =
ElmUiFramework
type Theme
= ElmUiFramework
| Template
| Material
toStyle : Theme -> Style msg
toStyle theme =
case theme of
ElmUiFramework ->
Data.Style.ElmUiFramework.style
Template ->
Data.Style.Template.style
Material ->
Data.Style.Material.style Data.Style.Material.defaultPalette

View File

@ -3,19 +3,19 @@ module Example.Button exposing (Model, Msg, init, subscriptions, update, view)
import Element exposing (Element)
import FeatherIcons
import Widget
import Widget.Style exposing (ButtonStyle)
import Widget.Style exposing (ButtonStyle, RowStyle)
type alias Style style msg =
{ style
| primaryButton : ButtonStyle msg
, button : ButtonStyle msg
, row : RowStyle msg
}
type alias Model =
{ isButtonEnabled : Bool
}
type Model
= IsButtonEnabled Bool
type Msg
@ -24,17 +24,16 @@ type Msg
init : ( Model, Cmd Msg )
init =
( { isButtonEnabled = True
}
( IsButtonEnabled True
, Cmd.none
)
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
update msg _ =
case msg of
ChangedButtonStatus bool ->
( { model | isButtonEnabled = bool }
( IsButtonEnabled bool
, Cmd.none
)
@ -45,7 +44,7 @@ subscriptions _ =
view : (Msg -> msg) -> Style style msg -> Model -> Element msg
view msgMapper style model =
view msgMapper style (IsButtonEnabled isButtonEnabled) =
[ Widget.button style.primaryButton
{ text = "disable me"
, icon =
@ -55,7 +54,7 @@ view msgMapper style model =
|> Element.html
|> Element.el []
, onPress =
if model.isButtonEnabled then
if isButtonEnabled then
ChangedButtonStatus False
|> msgMapper
|> Just
@ -77,7 +76,4 @@ view msgMapper style model =
|> Just
}
]
|> Element.row
[ Element.spaceEvenly
, Element.width <| Element.fill
]
|> Widget.row style.row

View File

@ -0,0 +1,93 @@
module Example.Dialog exposing (Model, Msg, init, subscriptions, update, view)
import Element exposing (Element)
import FeatherIcons
import Widget
import Widget.Style exposing (ButtonStyle, DialogStyle)
type alias Style style msg =
{ style
| dialog : DialogStyle msg
, primaryButton : ButtonStyle msg
}
type Model =
IsOpen Bool
type Msg
= OpenDialog Bool
init : ( Model, Cmd Msg )
init =
( IsOpen True
, Cmd.none
)
update : Msg -> Model -> ( Model, Cmd Msg )
update msg _ =
case msg of
OpenDialog bool ->
( IsOpen bool
, Cmd.none
)
subscriptions : Model -> Sub Msg
subscriptions _ =
Sub.none
view : (Msg -> msg) -> Style style msg -> Model -> Element msg
view msgMapper style (IsOpen isOpen) =
Widget.button style.primaryButton
{ text = "show Dialog"
, icon =
FeatherIcons.eye
|> FeatherIcons.withSize 16
|> FeatherIcons.toHtml []
|> Element.html
|> Element.el []
, onPress =
OpenDialog True
|> msgMapper
|> Just
}
|> Element.el
([ Element.height <| Element.minimum 200 <| Element.fill
, Element.width <| Element.minimum 400 <| Element.fill
]
++ (if isOpen then
{ body =
"This is a dialog window"
|> Element.text
|> List.singleton
|> Element.paragraph []
, title = Just "Dialog"
, accept =
Just
{ text = "Ok"
, onPress =
Just <|
msgMapper <|
OpenDialog False
}
, dismiss =
Just
{ text = "Dismiss"
, onPress =
Just <|
msgMapper <|
OpenDialog False
}
}
|> Widget.dialog style.dialog
else
[]
)
)

View File

@ -11,8 +11,8 @@ type alias Style style msg =
}
type alias Model =
{ isExpanded : Bool }
type Model
= IsExpanded Bool
type Msg
@ -21,18 +21,16 @@ type Msg
init : ( Model, Cmd Msg )
init =
( { isExpanded = False }
( IsExpanded False
, Cmd.none
)
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
update msg _ =
case msg of
ToggleCollapsable bool ->
( { model
| isExpanded = bool
}
( IsExpanded bool
, Cmd.none
)
@ -43,9 +41,9 @@ subscriptions _ =
view : (Msg -> msg) -> Style style msg -> Model -> Element msg
view msgMapper style model =
view msgMapper style (IsExpanded isExpanded) =
{ onToggle = ToggleCollapsable >> msgMapper
, isExpanded = model.isExpanded
, isExpanded = isExpanded
, icon = Element.none
, text = "Title"
, content = Element.text <| "Hello World"

View File

@ -0,0 +1,47 @@
module Example.List exposing (Model, Msg, init, subscriptions, update, view)
import Element exposing (Element)
import Widget
import Widget.Style exposing (ColumnStyle)
type alias Style style msg =
{ style
| cardColumn : ColumnStyle msg
}
type alias Model =
()
type alias Msg =
Never
init : ( Model, Cmd Msg )
init =
( ()
, Cmd.none
)
update : Msg -> Model -> ( Model, Cmd Msg )
update _ () =
( ()
, Cmd.none
)
subscriptions : Model -> Sub Msg
subscriptions () =
Sub.none
view : (Msg -> msg) -> Style style msg -> Model -> Element msg
view _ style () =
[ Element.text <| "A"
, Element.text <| "B"
, Element.text <| "C"
]
|> Widget.column style.cardColumn

View File

@ -0,0 +1,88 @@
module Example.Modal exposing (Model, Msg, init, subscriptions, update, view)
import Element exposing (Element)
import FeatherIcons
import Widget
import Widget.Style exposing (ButtonStyle, ColumnStyle)
type alias Style style msg =
{ style
| cardColumn : ColumnStyle msg
, primaryButton : ButtonStyle msg
}
type Model
= IsEnabled Bool
type Msg
= ToggleModal Bool
init : ( Model, Cmd Msg )
init =
( IsEnabled True
, Cmd.none
)
update : Msg -> Model -> ( Model, Cmd Msg )
update msg _ =
case msg of
ToggleModal bool ->
( IsEnabled bool
, Cmd.none
)
subscriptions : Model -> Sub Msg
subscriptions _ =
Sub.none
view : (Msg -> msg) -> Style style msg -> Model -> Element msg
view msgMapper style (IsEnabled isEnabled) =
Widget.button style.primaryButton
{ text = "show Modal"
, icon =
FeatherIcons.eye
|> FeatherIcons.withSize 16
|> FeatherIcons.toHtml []
|> Element.html
|> Element.el []
, onPress =
ToggleModal True
|> msgMapper
|> Just
}
|> Element.el
([ Element.height <| Element.minimum 200 <| Element.fill
, Element.width <| Element.minimum 400 <| Element.fill
]
++ (if isEnabled then
Widget.modal
{ onDismiss =
ToggleModal False
|> msgMapper
|> Just
, content =
"Click on the area around this box to close it."
|> Element.text
|> List.singleton
|> Element.paragraph []
|> List.singleton
|> Widget.column style.cardColumn
|> Element.el
[ Element.height <| Element.px 100
, Element.width <| Element.px 250
, Element.centerX
, Element.centerY
]
}
else
[]
)
)

View File

@ -13,9 +13,8 @@ type alias Style style msg =
}
type alias Model =
{ selected : Set Int
}
type Model
= Selected (Set Int)
type Msg
@ -24,25 +23,23 @@ type Msg
init : ( Model, Cmd Msg )
init =
( { selected = Set.empty }
( Selected <| Set.empty
, Cmd.none
)
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
update msg (Selected selected) =
case msg of
ChangedSelected int ->
( { model
| selected =
model.selected
|> (if model.selected |> Set.member int then
Set.remove int
( selected
|> (if selected |> Set.member int then
Set.remove int
else
Set.insert int
)
}
else
Set.insert int
)
|> Selected
, Cmd.none
)
@ -53,8 +50,8 @@ subscriptions _ =
view : (Msg -> msg) -> Style style msg -> Model -> Element msg
view msgMapper style model =
{ selected = model.selected
view msgMapper style (Selected selected) =
{ selected = selected
, options =
[ 1, 2, 42 ]
|> List.map

View File

@ -1,7 +1,6 @@
module Example.Select exposing (Model, Msg, init, subscriptions, update, view)
import Element exposing (Attribute, Element)
import FeatherIcons
import Element exposing (Element)
import Widget
import Widget.Style exposing (ButtonStyle, RowStyle)
@ -13,8 +12,8 @@ type alias Style style msg =
}
type alias Model =
{ selected : Maybe Int }
type Model
= Selected (Maybe Int)
type Msg
@ -23,18 +22,16 @@ type Msg
init : ( Model, Cmd Msg )
init =
( { selected = Nothing }
( Selected Nothing
, Cmd.none
)
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
update msg _ =
case msg of
ChangedSelected int ->
( { model
| selected = Just int
}
( Selected <| Just int
, Cmd.none
)
@ -45,8 +42,8 @@ subscriptions _ =
view : (Msg -> msg) -> Style style msg -> Model -> Element msg
view msgMapper style model =
{ selected = model.selected
view msgMapper style (Selected selected) =
{ selected = selected
, options =
[ 1, 2, 42 ]
|> List.map

View File

@ -0,0 +1,89 @@
module Example.SortTable exposing (Model, Msg, init, subscriptions, update, view)
import Element exposing (Element)
import Widget
import Widget.Style exposing (SortTableStyle)
type alias Style style msg =
{ style
| sortTable : SortTableStyle msg
}
type alias Model =
{ title : String
, asc : Bool
}
type Msg
= ChangedSorting String
init : ( Model, Cmd Msg )
init =
( { title = "Name", asc = True }
, Cmd.none
)
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
ChangedSorting string ->
( { title = string
, asc =
if model.title == string then
not model.asc
else
True
}
, Cmd.none
)
subscriptions : Model -> Sub Msg
subscriptions _ =
Sub.none
view : (Msg -> msg) -> Style style msg -> Model -> Element msg
view msgMapper style model =
Widget.sortTable style.sortTable
{ content =
[ { id = 1, name = "Antonio", rating = 2.456, hash = Nothing }
, { id = 2, name = "Ana", rating = 1.34, hash = Just "45jf" }
, { id = 3, name = "Alfred", rating = 4.22, hash = Just "6fs1" }
, { id = 4, name = "Thomas", rating = 3, hash = Just "k52f" }
]
, columns =
[ Widget.intColumn
{ title = "Id"
, value = .id
, toString = \int -> "#" ++ String.fromInt int
, width = Element.fill
}
, Widget.stringColumn
{ title = "Name"
, value = .name
, toString = identity
, width = Element.fill
}
, Widget.floatColumn
{ title = "Rating"
, value = .rating
, toString = String.fromFloat
, width = Element.fill
}
, Widget.unsortableColumn
{ title = "Hash"
, toString = .hash >> Maybe.withDefault "None"
, width = Element.fill
}
]
, asc = model.asc
, sortBy = model.title
, onChange = ChangedSorting >> msgMapper
}

View File

@ -11,9 +11,8 @@ type alias Style style msg =
}
type alias Model =
{ selected : Maybe Int
}
type Model
= Selected (Maybe Int)
type Msg
@ -22,17 +21,16 @@ type Msg
init : ( Model, Cmd Msg )
init =
( { selected = Nothing
}
( Selected Nothing
, Cmd.none
)
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
update msg _ =
case msg of
ChangedTab int ->
( { model | selected = Just int }
( Selected <| Just int
, Cmd.none
)
@ -43,10 +41,10 @@ subscriptions _ =
view : (Msg -> msg) -> Style style msg -> Model -> Element msg
view msgMapper style model =
view msgMapper style (Selected selected) =
Widget.tab style.tab
{ tabs =
{ selected = model.selected
{ selected = selected
, options =
[ 1, 2, 3 ]
|> List.map
@ -58,8 +56,8 @@ view msgMapper style model =
, onSelect = ChangedTab >> msgMapper >> Just
}
, content =
\selected ->
(case selected of
\s ->
(case s of
Just 0 ->
"This is Tab 1"

View File

@ -0,0 +1,104 @@
module Example.TextInput exposing (Model, Msg, init, subscriptions, update, view)
import Element exposing (Element)
import Set exposing (Set)
import Widget
import Widget.Style exposing (ColumnStyle, TextInputStyle)
type alias Style style msg =
{ style
| textInput : TextInputStyle msg
, column : ColumnStyle msg
}
type alias Model =
{ chipTextInput : Set String
, textInput : String
}
type Msg
= ToggleTextInputChip String
| SetTextInput String
init : ( Model, Cmd Msg )
init =
( { chipTextInput = Set.empty
, textInput = ""
}
, Cmd.none
)
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
ToggleTextInputChip string ->
( { model
| chipTextInput =
model.chipTextInput
|> (if model.chipTextInput |> Set.member string then
Set.remove string
else
Set.insert string
)
}
, Cmd.none
)
SetTextInput string ->
( { model | textInput = string }, Cmd.none )
subscriptions : Model -> Sub Msg
subscriptions _ =
Sub.none
view : (Msg -> msg) -> Style style msg -> Model -> Element msg
view msgMapper style model =
[ { chips =
model.chipTextInput
|> Set.toList
|> List.map
(\string ->
{ icon = Element.none
, text = string
, onPress =
string
|> ToggleTextInputChip
|> msgMapper
|> Just
}
)
, text = model.textInput
, placeholder = Nothing
, label = "Chips"
, onChange = SetTextInput >> msgMapper
}
|> Widget.textInput style.textInput
, model.chipTextInput
|> Set.diff
([ "A", "B", "C" ]
|> Set.fromList
)
|> Set.toList
|> List.map
(\string ->
Widget.button style.textInput.chipButton
{ onPress =
string
|> ToggleTextInputChip
|> msgMapper
|> Just
, text = string
, icon = Element.none
}
)
|> Element.wrappedRow [ Element.spacing 10 ]
]
|> Widget.column style.column

View File

@ -3,148 +3,205 @@ module Icons exposing
, chevronDown
, chevronLeft
, chevronRight
, chevronUp
, circle
, github
, menu
, moreVertical
, penTool
, repeat
, search
, slash
, square
, triangle
, chevronUp
, penTool
)
import Html exposing (Html)
import Svg exposing (Svg, svg)
import Svg.Attributes exposing (..)
import Svg.Attributes as Attributes
svgFeatherIcon : String -> List (Svg msg) -> Html msg
svgFeatherIcon className =
svg
[ class <| "feather feather-" ++ className
, fill "none"
, height "16"
, stroke "currentColor"
, strokeLinecap "round"
, strokeLinejoin "round"
, strokeWidth "2"
, viewBox "0 0 24 24"
, width "16"
[ Attributes.class <| "feather feather-" ++ className
, Attributes.fill "none"
, Attributes.height "16"
, Attributes.stroke "currentColor"
, Attributes.strokeLinecap "round"
, Attributes.strokeLinejoin "round"
, Attributes.strokeWidth "2"
, Attributes.viewBox "0 0 24 24"
, Attributes.width "16"
]
chevronDown : Html msg
chevronDown =
svgFeatherIcon "chevron-down"
[ Svg.polyline [ points "6 9 12 15 18 9" ] []
[ Svg.polyline [ Attributes.points "6 9 12 15 18 9" ] []
]
chevronRight : Html msg
chevronRight =
svgFeatherIcon "chevron-right"
[ Svg.polyline [ points "9 18 15 12 9 6" ] []
[ Svg.polyline [ Attributes.points "9 18 15 12 9 6" ] []
]
chevronLeft : Html msg
chevronLeft =
svgFeatherIcon "chevron-left"
[ Svg.polyline [ points "15 18 9 12 15 6" ] []
[ Svg.polyline [ Attributes.points "15 18 9 12 15 6" ] []
]
chevronUp : Html msg
chevronUp =
svgFeatherIcon "chevron-up"
[ Svg.polyline [ points "18 15 12 9 6 15" ] []
[ Svg.polyline [ Attributes.points "18 15 12 9 6 15" ] []
]
repeat : Html msg
repeat =
svgFeatherIcon "repeat"
[ Svg.polyline [ points "17 1 21 5 17 9" ] []
, Svg.path [ d "M3 11V9a4 4 0 0 1 4-4h14" ] []
, Svg.polyline [ points "7 23 3 19 7 15" ] []
, Svg.path [ d "M21 13v2a4 4 0 0 1-4 4H3" ] []
[ Svg.polyline [ Attributes.points "17 1 21 5 17 9" ] []
, Svg.path [ Attributes.d "M3 11V9a4 4 0 0 1 4-4h14" ] []
, Svg.polyline [ Attributes.points "7 23 3 19 7 15" ] []
, Svg.path [ Attributes.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" ] []
[ Svg.path [ Attributes.d "M12 19l7-7 3 3-7 7-3-3z" ] []
, Svg.path [ Attributes.d "M18 13l-1.5-7.5L2 2l3.5 14.5L13 18l5-5z" ] []
, Svg.path [ Attributes.d "M2 2l7.586 7.586" ] []
, Svg.circle
[ Attributes.cx "11"
, Attributes.cy "11"
, Attributes.r "2"
]
[]
]
book : Html msg
book =
svgFeatherIcon "book"
[ Svg.path [ d "M4 19.5A2.5 2.5 0 0 1 6.5 17H20" ] []
, Svg.path [ d "M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z" ] []
[ Svg.path [ Attributes.d "M4 19.5A2.5 2.5 0 0 1 6.5 17H20" ] []
, Svg.path [ Attributes.d "M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z" ] []
]
github : Html msg
github =
svgFeatherIcon "github"
[ Svg.path [ d "M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22" ] []
[ Svg.path [ Attributes.d "M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22" ] []
]
menu : Html msg
menu =
svgFeatherIcon "menu"
[ Svg.line [ x1 "3", y1 "12", x2 "21", y2 "12" ] []
, Svg.line [ x1 "3", y1 "6", x2 "21", y2 "6" ] []
, Svg.line [ x1 "3", y1 "18", x2 "21", y2 "18" ] []
[ Svg.line
[ Attributes.x1 "3"
, Attributes.y1 "12"
, Attributes.x2 "21"
, Attributes.y2 "12"
]
[]
, Svg.line
[ Attributes.x1 "3"
, Attributes.y1 "6"
, Attributes.x2 "21"
, Attributes.y2 "6"
]
[]
, Svg.line
[ Attributes.x1 "3"
, Attributes.y1 "18"
, Attributes.x2 "21"
, Attributes.y2 "18"
]
[]
]
moreVertical : Html msg
moreVertical =
svgFeatherIcon "more-vertical"
[ Svg.circle [ cx "12", cy "12", r "1" ] []
, Svg.circle [ cx "12", cy "5", r "1" ] []
, Svg.circle [ cx "12", cy "19", r "1" ] []
[ Svg.circle [ Attributes.cx "12", Attributes.cy "12", Attributes.r "1" ] []
, Svg.circle [ Attributes.cx "12", Attributes.cy "5", Attributes.r "1" ] []
, Svg.circle [ Attributes.cx "12", Attributes.cy "19", Attributes.r "1" ] []
]
circle : Html msg
circle =
svgFeatherIcon "circle"
[ Svg.circle [ cx "12", cy "12", r "10" ] []
[ Svg.circle [ Attributes.cx "12", Attributes.cy "12", Attributes.r "10" ] []
]
slash : Html msg
slash =
svgFeatherIcon "slash"
[ Svg.circle [ cx "12", cy "12", r "10" ] []
, Svg.line [ x1 "4.93", y1 "4.93", x2 "19.07", y2 "19.07" ] []
[ Svg.circle
[ Attributes.cx "12"
, Attributes.cy "12"
, Attributes.r "10"
]
[]
, Svg.line
[ Attributes.x1 "4.93"
, Attributes.y1 "4.93"
, Attributes.x2 "19.07"
, Attributes.y2 "19.07"
]
[]
]
triangle : Html msg
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 [ Attributes.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 =
svgFeatherIcon "square"
[ Svg.rect [ Svg.Attributes.x "3", y "3", width "18", height "18", rx "2", ry "2" ] []
[ Svg.rect
[ Attributes.x "3"
, Attributes.y "3"
, Attributes.width "18"
, Attributes.height "18"
, Attributes.rx "2"
, Attributes.ry "2"
]
[]
]
search : Html msg
search =
svgFeatherIcon "search"
[ Svg.circle [ cx "11", cy "11", r "8" ] []
, Svg.line [ x1 "21", y1 "21", x2 "16.65", y2 "16.65" ] []
[ Svg.circle
[ Attributes.cx "11"
, Attributes.cy "11"
, Attributes.r "8"
]
[]
, Svg.line
[ Attributes.x1 "21"
, Attributes.y1 "21"
, Attributes.x2 "16.65"
, Attributes.y2 "16.65"
]
[]
]

View File

@ -6,34 +6,21 @@ import Browser.Dom as Dom exposing (Viewport)
import Browser.Events as Events
import Browser.Navigation as Navigation
import Data.Section as Section exposing (Section(..))
import Data.Style as Style exposing (Style)
import Data.Style exposing (Style)
import Data.Theme as Theme exposing (Theme(..))
import Element exposing (Attribute, DeviceClass(..), Element)
import Element.Border as Border
import Element.Font as Font
import Element.Input as Input
import Element exposing (DeviceClass(..))
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 Html exposing (Html)
import Html.Attributes as Attributes
import Icons
import Layout exposing (Layout, Part)
import Reusable
import Set exposing (Set)
import Stateless
import Task
import Time
import Widget
import Widget.Layout as Layout exposing (Layout, Part)
import Widget.ScrollingNav as ScrollingNav
import Widget.Snackbar as Snackbar
import Widget.Style exposing (ButtonStyle)
type alias LoadedModel =
@ -41,7 +28,10 @@ type alias LoadedModel =
, scrollingNav : ScrollingNav.Model Section
, layout : Layout LoadedMsg
, displayDialog : Bool
, window : { height : Int, width : Int }
, window :
{ height : Int
, width : Int
}
, search :
{ raw : String
, current : String
@ -110,7 +100,7 @@ initialModel { viewport } =
, current = ""
, remaining = 0
}
, theme = ElmUiFramework
, theme = Material
}
, [ cmd
, statelessCmd |> Cmd.map StatelessSpecific
@ -171,17 +161,17 @@ view model =
(\section ->
(case section of
ReusableViews ->
Reusable.view m.theme
{ addSnackbar = AddSnackbar
Reusable.view
{ theme = m.theme
, addSnackbar = AddSnackbar
}
StatelessViews ->
Stateless.view m.theme
{ msgMapper = StatelessSpecific
, showDialog = ToggleDialog True
, changedSheet = ChangedSidebar
Stateless.view
{ theme = m.theme
, msgMapper = StatelessSpecific
, model = m.stateless
}
m.stateless
)
|> (\{ title, description, items } ->
[ Element.el Heading.h2 <| Element.text <| title
@ -213,12 +203,17 @@ view model =
]
|> Element.column Grid.simple
, more
|> Element.el [ Element.height <| Element.fill ]
|> Element.el
[ Element.width <| Element.fill
]
]
|> Widget.column style.cardColumn
)
|> Element.wrappedRow
(Grid.simple ++ [ Element.height <| Element.shrink ])
(Grid.simple
++ [ Element.height <| Element.shrink
]
)
]
|> Element.column (Grid.section ++ [ Element.centerX ])
)
@ -266,6 +261,15 @@ view model =
, text = "Template Theme"
, icon = Icons.penTool |> Element.html |> Element.el []
}
, { onPress =
if m.theme /= Material then
Just <| SetTheme <| Material
else
Nothing
, text = "Material Theme"
, icon = Icons.penTool |> Element.html |> Element.el []
}
, { onPress = Nothing
, text = "Placeholder"
, icon = Icons.circle |> Element.html |> Element.el []
@ -428,7 +432,7 @@ update msg model =
subscriptions : Model -> Sub Msg
subscriptions model =
subscriptions _ =
Sub.batch
[ Time.every 50 (always (TimePassed 50))
, Events.onResize (\h w -> Resized { height = h, width = w })

View File

@ -1,40 +1,13 @@
module Reusable exposing ( view)
module Reusable exposing (view)
import Browser
import Element exposing (Color, Element)
import Element.Background as Background
import Element.Font as Font
import Element.Input as Input
import Framework
import Framework.Button as Button
import Framework.Card as Card
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.ScrollingNav as ScrollingNav
import Widget.Snackbar as Snackbar
import Data.Style exposing (Style)
import Data.Theme as Theme exposing (Theme)
import Element exposing (Element)
import Framework.Grid as Grid
import Widget
type alias Item =
{ name : String
, amount : Int
, price : Float
}
snackbar : Style msg -> (( String, Bool ) -> msg) -> ( String, Element msg,Element msg )
snackbar : Style msg -> (( String, Bool ) -> msg) -> ( String, Element msg, Element msg )
snackbar style addSnackbar =
( "Snackbar"
, [ Widget.button style.button
@ -45,7 +18,7 @@ snackbar style addSnackbar =
, False
)
, text = "Add Notification"
, icon =Element.none
, icon = Element.none
}
, Widget.button style.button
{ onPress =
@ -63,11 +36,8 @@ snackbar style addSnackbar =
)
scrollingNavCard : Style msg -> ( String, Element msg, Element msg )
scrollingNavCard style =
scrollingNavCard _ =
( "Scrolling Nav"
, Element.text "Resize the screen and open the side-menu. Then start scrolling to see the scrolling navigation in action."
|> List.singleton
@ -76,23 +46,35 @@ scrollingNavCard style =
)
layout : Style msg -> ( String, Element msg, Element msg )
layout _ =
( "Layout"
, Element.text "The layout combines the menu bar, both side bar, the dialog window and the snackbar. Try using all of them and also try resizing the window to see how they interact with each other."
|> List.singleton
|> Element.paragraph []
, Element.none
)
view :
Theme ->
{ addSnackbar : ( String, Bool ) -> msg
{ theme : Theme
, addSnackbar : ( String, Bool ) -> msg
}
->
{ title : String
, description : String
, items : List ( String, Element msg,Element msg )
, items : List ( String, Element msg, Element msg )
}
view theme { addSnackbar } =
view { theme, addSnackbar } =
let
style = Theme.toStyle theme
style =
Theme.toStyle theme
in
{ title = "Reusable Views"
, description = "Reusable views have an internal state but no update function. You will need to do some wiring, but nothing complicated."
, items =
[ snackbar style addSnackbar
, scrollingNavCard style
, layout style
]
}

View File

@ -1,37 +1,19 @@
module Stateless exposing (Model, Msg, init, update, view)
import Array
import Data.Example as Example
import Data.Style exposing (Style)
import Data.Theme as Theme exposing (Theme)
import Element exposing (Element)
import Element.Background as Background
import Framework.Card as Card
import Framework.Color as Color
import Framework.Grid as Grid
import Heroicons.Solid as Heroicons
import Html.Attributes as Attributes
import Icons
import Layout exposing (Part(..))
import Set exposing (Set)
import Widget
import Widget.Layout exposing (Part(..))
type alias Model =
{ chipTextInput : Set String
, carousel : Int
, textInput : String
, table : { title : String, asc : Bool }
{ carousel : Int
, example : Example.Model
}
type Msg
= ToggleTextInputChip String
| SetCarousel Int
| SetTextInput String
| ChangedSorting String
| ExampleSpecific Example.Msg
= ExampleSpecific Example.Msg
| Idle
@ -41,10 +23,7 @@ init =
( example, cmd ) =
Example.init
in
( { chipTextInput = Set.empty
, carousel = 0
, textInput = ""
, table = { title = "Name", asc = True }
( { carousel = 0
, example = example
}
, cmd |> Cmd.map ExampleSpecific
@ -63,310 +42,24 @@ update msg model =
, exampleCmd |> Cmd.map ExampleSpecific
)
ToggleTextInputChip string ->
( { model
| chipTextInput =
model.chipTextInput
|> (if model.chipTextInput |> Set.member string then
Set.remove string
else
Set.insert string
)
}
, Cmd.none
)
SetCarousel int ->
( if (int < 0) || (int > 3) then
model
else
{ model
| carousel = int
}
, Cmd.none
)
SetTextInput string ->
( { model | textInput = string }, Cmd.none )
ChangedSorting string ->
( { model
| table =
{ title = string
, asc =
if model.table.title == string then
not model.table.asc
else
True
}
}
, Cmd.none
)
Idle ->
( model, Cmd.none )
modal : Style msg -> (Maybe Part -> msg) -> Model -> ( String, Element msg, Element msg )
modal style changedSheet _ =
( "Modal"
, [ Widget.button style.button
{ onPress = Just <| changedSheet <| Just LeftSheet
, text = "show left sheet"
, icon = Element.none
}
, Widget.button style.button
{ onPress = Just <| changedSheet <| Just RightSheet
, text = "show right sheet"
, icon = Element.none
}
]
|> Element.column Grid.simple
, Element.none
)
dialog : Style msg -> msg -> Model -> ( String, Element msg, Element msg )
dialog style showDialog _ =
( "Dialog"
, Widget.button style.button
{ onPress = Just showDialog
, text = "Show dialog"
, icon = Element.none
}
, Element.none
)
carousel : Style Msg -> Model -> ( String, Element Msg, Element Msg )
carousel style model =
( "Carousel"
, Widget.carousel
{ content = ( Color.cyan, [ Color.yellow, Color.green, Color.red ] |> Array.fromList )
, current = model.carousel
, label =
\c ->
[ Element.el [ Element.centerY ] <|
Widget.iconButton style.button
{ onPress =
model.carousel
- 1
|> (\i ->
if i < 0 then
Nothing
else
SetCarousel i
|> Just
)
, icon =
Icons.chevronLeft
|> Element.html
|> Element.el []
, text = "Previous"
}
, Element.el
(Card.simple
++ [ Background.color <| c
, Element.height <| Element.px <| 100
, Element.width <| Element.px <| 100
]
)
<|
Element.none
, Element.el [ Element.centerY ] <|
Widget.iconButton style.button
{ onPress =
model.carousel
+ 1
|> (\i ->
if i >= 4 then
Nothing
else
SetCarousel i
|> Just
)
, icon =
Icons.chevronRight
|> Element.html
|> Element.el []
, text = "Next"
}
]
|> Element.row (Grid.simple ++ [ Element.centerX, Element.width <| Element.shrink ])
}
, Element.none
)
textInput : Style Msg -> Model -> ( String, Element Msg, Element Msg )
textInput style model =
( "Chip Text Input"
, [ { chips =
model.chipTextInput
|> Set.toList
|> List.map
(\string ->
{ icon = Element.none
, text = string
, onPress =
string
|> ToggleTextInputChip
|> Just
}
)
, text = model.textInput
, placeholder = Nothing
, label = "Chips"
, onChange = SetTextInput
}
|> Widget.textInput style.textInput
, model.chipTextInput
|> Set.diff
([ "A", "B", "C" ]
|> Set.fromList
)
|> Set.toList
|> List.map
(\string ->
Widget.button style.textInput.chipButton
{ onPress =
string
|> ToggleTextInputChip
|> Just
, text = string
, icon = Element.none
}
)
|> Element.wrappedRow [ Element.spacing 10 ]
]
|> Element.column Grid.simple
, [ Element.row Grid.spacedEvenly
[ "Nothing Selected"
|> Element.text
|> Element.el [ Element.width <| Element.fill ]
, { chips = []
, text = ""
, placeholder = Nothing
, label = "Label"
, onChange = always Idle
}
|> Widget.textInput style.textInput
]
, Element.row Grid.spacedEvenly
[ "Some chips"
|> Element.text
|> Element.el [ Element.width <| Element.fill ]
, { chips =
[ { icon = Icons.triangle |> Element.html |> Element.el []
, text = "A"
, onPress = Just Idle
}
, { icon = Icons.circle |> Element.html |> Element.el []
, text = "B"
, onPress = Just Idle
}
]
, text = ""
, placeholder = Nothing
, label = "Label"
, onChange = always Idle
}
|> Widget.textInput style.textInput
]
]
|> Element.column Grid.simple
)
list : Style Msg -> Model -> ( String, Element Msg, Element Msg )
list style _ =
( "List"
, [ Element.text <| "A"
, Element.text <| "B"
, Element.text <| "C"
]
|> Widget.column style.cardColumn
, Element.none
)
sortTable : Style Msg -> Model -> ( String, Element Msg, Element Msg )
sortTable _ model =
( "Sort Table"
, Widget.sortTable
{ containerTable = Grid.simple
, headerButton =
{ container = []
, labelRow = []
, ifDisabled = []
, ifActive = []
}
, ascIcon = Heroicons.cheveronUp [ Attributes.width 16 ] |> Element.html
, descIcon = Heroicons.cheveronDown [ Attributes.width 16 ] |> Element.html
, defaultIcon = Element.none
}
{ content =
[ { id = 1, name = "Antonio", rating = 2.456 }
, { id = 2, name = "Ana", rating = 1.34 }
, { id = 3, name = "Alfred", rating = 4.22 }
, { id = 4, name = "Thomas", rating = 3 }
]
, columns =
[ Widget.intColumn
{ title = "Id"
, value = .id
, toString = \int -> "#" ++ String.fromInt int
, width = Element.fill
}
, Widget.stringColumn
{ title = "Name"
, value = .name
, toString = identity
, width = Element.fill
}
, Widget.floatColumn
{ title = "rating"
, value = .rating
, toString = String.fromFloat
, width = Element.fill
}
]
, asc = model.table.asc
, sortBy = model.table.title
, onChange = ChangedSorting
}
, Element.none
)
view :
Theme
->
{ msgMapper : Msg -> msg
, showDialog : msg
, changedSheet : Maybe Part -> msg
}
-> Model
{ theme : Theme
, msgMapper : Msg -> msg
, model : Model
}
->
{ title : String
, description : String
, items : List ( String, Element msg, Element msg )
}
view theme { msgMapper, showDialog, changedSheet } model =
view { theme, msgMapper, model } =
let
style =
Theme.toStyle theme
map ( a, b, c ) =
( a
, b |> Element.map msgMapper
, c |> Element.map msgMapper
)
in
{ title = "Stateless Views"
, description = "Stateless views are simple functions that view some content. No wiring required."
@ -377,11 +70,4 @@ view theme { msgMapper, showDialog, changedSheet } model =
, style = style
, model = model.example
}
++ [ modal style changedSheet model
, carousel style model |> map
, dialog style showDialog model
, textInput style model |> map
, list style model |> map
, sortTable style model |> map
]
}

View File

@ -1,339 +1,280 @@
module View.Test exposing (expansionPanel, iconButton, multiSelect, select, tab)
module View.Test exposing (button, dialog, expansionPanel, list, modal, multiSelect, select, sortTable, tab, textInput)
import Array
import Data.Style exposing (Style)
import Data.Theme as Theme exposing (Theme)
import Element exposing (Element)
import Element.Background as Background
import Framework.Card as Card
import Framework.Color as Color
import Framework.Grid as Grid
import Heroicons.Solid as Heroicons
import Html.Attributes as Attributes
import Icons
import Layout exposing (Part(..))
import Set exposing (Set)
import Set
import Widget
import Widget.Layout exposing (Part(..))
iconButton : msg -> Style msg -> List (Element msg)
iconButton idle style =
[ Element.row Grid.spacedEvenly
[ "Button"
|> Element.text
, Widget.button style.button
button : msg -> Style msg -> List ( String, Element msg )
button idle style =
[ ( "Button"
, Widget.button style.button
{ text = "Button"
, icon = Icons.triangle |> Element.html |> Element.el []
, onPress = Just idle
}
]
, Element.row Grid.spacedEvenly
[ "Text button"
|> Element.text
, Widget.textButton style.button
)
, ( "Text button"
, Widget.textButton style.button
{ text = "Button"
, onPress = Just idle
}
]
, Element.row Grid.spacedEvenly
[ "Icon button"
|> Element.text
, Widget.iconButton style.button
)
, ( "Icon button"
, Widget.iconButton style.button
{ text = "Button"
, icon = Icons.triangle |> Element.html |> Element.el []
, onPress = Just idle
}
]
, Element.row Grid.spacedEvenly
[ "Disabled button"
|> Element.text
, Widget.button style.button
)
, ( "Disabled button"
, Widget.button style.button
{ text = "Button"
, icon = Icons.triangle |> Element.html |> Element.el []
, onPress = Nothing
}
]
, Element.row Grid.spacedEvenly
[ "Inactive Select button"
|> Element.text
, Widget.selectButton style.button
)
, ( "Inactive Select button"
, Widget.selectButton style.button
( False
, { text = "Button"
, icon = Icons.triangle |> Element.html |> Element.el []
, onPress = Just idle
}
)
]
, Element.row Grid.spacedEvenly
[ "Active Select button"
|> Element.text
, Widget.selectButton style.button
)
, ( "Active Select button"
, Widget.selectButton style.button
( True
, { text = "Button"
, icon = Icons.triangle |> Element.html |> Element.el []
, onPress = Just idle
}
)
]
)
]
select : msg -> Style msg -> List (Element msg)
select : msg -> Style msg -> List ( String, Element msg )
select idle style =
[ Element.row Grid.spacedEvenly
[ "First selected"
|> Element.text
|> Element.el [ Element.width <| Element.fill ]
, { selected = Just 0
, options =
[ 1, 2, 42 ]
|> List.map
(\int ->
{ text = String.fromInt int
, icon = Element.none
}
)
, onSelect = always idle >> Just
}
[ ( "First selected"
, { selected = Just 0
, options =
[ 1, 2, 42 ]
|> List.map
(\int ->
{ text = String.fromInt int
, icon = Element.none
}
)
, onSelect = always idle >> Just
}
|> Widget.select
|> Widget.buttonRow
{ list = style.row
, button = style.button
}
]
, Element.row Grid.spacedEvenly
[ "Nothing selected"
|> Element.text
|> Element.el [ Element.width <| Element.fill ]
, { selected = Nothing
, options =
[ 1, 2, 42 ]
|> List.map
(\int ->
{ text = String.fromInt int
, icon = Element.none
}
)
, onSelect = always idle >> Just
}
)
, ( "Nothing selected"
, { selected = Nothing
, options =
[ 1, 2, 42 ]
|> List.map
(\int ->
{ text = String.fromInt int
, icon = Element.none
}
)
, onSelect = always idle >> Just
}
|> Widget.select
|> Widget.buttonRow
{ list = style.row
, button = style.button
}
]
, Element.row Grid.spacedEvenly
[ "Invalid selection"
|> Element.text
|> Element.el [ Element.width <| Element.fill ]
, { selected = Just -1
, options =
[ 1, 2, 42 ]
|> List.map
(\int ->
{ text = String.fromInt int
, icon = Element.none
}
)
, onSelect = always idle >> Just
}
)
, ( "Invalid selection"
, { selected = Just -1
, options =
[ 1, 2, 42 ]
|> List.map
(\int ->
{ text = String.fromInt int
, icon = Element.none
}
)
, onSelect = always idle >> Just
}
|> Widget.select
|> Widget.buttonRow
{ list = style.row
, button = style.button
}
]
, Element.row Grid.spacedEvenly
[ "Disabled selection"
|> Element.text
|> Element.el [ Element.width <| Element.fill ]
, { selected = Just 0
, options =
[ 1, 2, 42 ]
|> List.map
(\int ->
{ text = String.fromInt int
, icon = Element.none
}
)
, onSelect = always Nothing
}
)
, ( "Disabled selection"
, { selected = Just 0
, options =
[ 1, 2, 42 ]
|> List.map
(\int ->
{ text = String.fromInt int
, icon = Element.none
}
)
, onSelect = always Nothing
}
|> Widget.select
|> Widget.buttonRow
{ list = style.row
, button = style.button
}
]
, Element.row Grid.spacedEvenly
[ "Empty Options"
|> Element.text
|> Element.el [ Element.width <| Element.fill ]
, { selected = Nothing
, options =
[]
|> List.map
(\int ->
{ text = String.fromInt int
, icon = Element.none
}
)
, onSelect = always idle >> Just
}
)
, ( "Empty Options"
, { selected = Nothing
, options =
[]
|> List.map
(\int ->
{ text = String.fromInt int
, icon = Element.none
}
)
, onSelect = always idle >> Just
}
|> Widget.select
|> Widget.buttonRow
{ list = style.row
, button = style.button
}
]
)
]
multiSelect : msg -> Style msg -> List (Element msg)
multiSelect : msg -> Style msg -> List ( String, Element msg )
multiSelect idle style =
[ Element.row Grid.spacedEvenly
[ "Some selected"
|> Element.text
|> Element.el [ Element.width <| Element.fill ]
, { selected = Set.fromList [ 0, 1 ]
, options =
[ 1, 2, 42 ]
|> List.map
(\int ->
{ text = String.fromInt int
, icon = Element.none
}
)
, onSelect = always idle >> Just
}
[ ( "Some selected"
, { selected = Set.fromList [ 0, 1 ]
, options =
[ 1, 2, 42 ]
|> List.map
(\int ->
{ text = String.fromInt int
, icon = Element.none
}
)
, onSelect = always idle >> Just
}
|> Widget.multiSelect
|> Widget.buttonRow
{ list = style.row
, button = style.button
}
]
, Element.row Grid.spacedEvenly
[ "Nothing selected"
|> Element.text
|> Element.el [ Element.width <| Element.fill ]
, { selected = Set.empty
, options =
[ 1, 2, 42 ]
|> List.map
(\int ->
{ text = String.fromInt int
, icon = Element.none
}
)
, onSelect = always idle >> Just
}
)
, ( "Nothing selected"
, { selected = Set.empty
, options =
[ 1, 2, 42 ]
|> List.map
(\int ->
{ text = String.fromInt int
, icon = Element.none
}
)
, onSelect = always idle >> Just
}
|> Widget.multiSelect
|> Widget.buttonRow
{ list = style.row
, button = style.button
}
]
, Element.row Grid.spacedEvenly
[ "Invalid selection"
|> Element.text
|> Element.el [ Element.width <| Element.fill ]
, { selected = Set.singleton -1
, options =
[ 1, 2, 42 ]
|> List.map
(\int ->
{ text = String.fromInt int
, icon = Element.none
}
)
, onSelect = always idle >> Just
}
)
, ( "Invalid selection"
, { selected = Set.singleton -1
, options =
[ 1, 2, 42 ]
|> List.map
(\int ->
{ text = String.fromInt int
, icon = Element.none
}
)
, onSelect = always idle >> Just
}
|> Widget.multiSelect
|> Widget.buttonRow
{ list = style.row
, button = style.button
}
]
, Element.row Grid.spacedEvenly
[ "Disabled selection"
|> Element.text
|> Element.el [ Element.width <| Element.fill ]
, { selected = Set.singleton 0
, options =
[ 1, 2, 42 ]
|> List.map
(\int ->
{ text = String.fromInt int
, icon = Element.none
}
)
, onSelect = always Nothing
}
)
, ( "Disabled selection"
, { selected = Set.singleton 0
, options =
[ 1, 2, 42 ]
|> List.map
(\int ->
{ text = String.fromInt int
, icon = Element.none
}
)
, onSelect = always Nothing
}
|> Widget.multiSelect
|> Widget.buttonRow
{ list = style.row
, button = style.button
}
]
, Element.row Grid.spacedEvenly
[ "Empty Options"
|> Element.text
|> Element.el [ Element.width <| Element.fill ]
, { selected = Set.empty
, options =
[]
|> List.map
(\int ->
{ text = String.fromInt int
, icon = Element.none
}
)
, onSelect = always idle >> Just
}
)
, ( "Empty Options"
, { selected = Set.empty
, options =
[]
|> List.map
(\int ->
{ text = String.fromInt int
, icon = Element.none
}
)
, onSelect = always idle >> Just
}
|> Widget.multiSelect
|> Widget.buttonRow
{ list = style.row
, button = style.button
}
]
)
]
expansionPanel : msg -> Style msg -> List (Element msg)
expansionPanel : msg -> Style msg -> List ( String, Element msg )
expansionPanel idle style =
[ Element.row Grid.spacedEvenly
[ "Collapsed"
|> Element.text
|> Element.el [ Element.width <| Element.fill ]
, { onToggle = always idle
, isExpanded = False
, icon = Icons.triangle |> Element.html |> Element.el []
, text = "Button"
, content = Element.text <| "Hidden Message"
}
[ ( "Collapsed"
, { onToggle = always idle
, isExpanded = False
, icon = Icons.triangle |> Element.html |> Element.el []
, text = "Button"
, content = Element.text <| "Hidden Message"
}
|> Widget.expansionPanel style.expansionPanel
]
, Element.row Grid.spacedEvenly
[ "Expanded"
|> Element.text
|> Element.el [ Element.width <| Element.fill ]
, { onToggle = always idle
, isExpanded = True
, icon = Icons.triangle |> Element.html |> Element.el []
, text = "Button"
, content = Element.text <| "Hidden Message"
}
)
, ( "Expanded"
, { onToggle = always idle
, isExpanded = True
, icon = Icons.triangle |> Element.html |> Element.el []
, text = "Button"
, content = Element.text <| "Hidden Message"
}
|> Widget.expansionPanel style.expansionPanel
]
)
]
tab : msg -> Style msg -> List (Element msg)
tab : msg -> Style msg -> List ( String, Element msg )
tab idle style =
[ Element.row Grid.spacedEvenly
[ "Nothing selected"
|> Element.text
|> Element.el [ Element.width <| Element.fill ]
, Widget.tab style.tab
[ ( "Nothing selected"
, Widget.tab style.tab
{ tabs =
{ selected = Nothing
, options =
@ -357,12 +298,9 @@ tab idle style =
)
|> Element.text
}
]
, Element.row Grid.spacedEvenly
[ "Tab selected"
|> Element.text
|> Element.el [ Element.width <| Element.fill ]
, Widget.tab style.tab
)
, ( "Tab selected"
, Widget.tab style.tab
{ tabs =
{ selected = Just 0
, options =
@ -386,5 +324,190 @@ tab idle style =
)
|> Element.text
}
]
)
]
sortTable : msg -> Style msg -> List ( String, Element msg )
sortTable idle style =
[ ( "Int column"
, Widget.sortTable style.sortTable
{ content =
[ { id = 1, name = "Antonio", rating = 2.456, hash = Nothing }
, { id = 2, name = "Ana", rating = 1.34, hash = Just "45jf" }
]
, columns =
[ Widget.intColumn
{ title = "Id"
, value = .id
, toString = \int -> "#" ++ String.fromInt int
, width = Element.fill
}
, Widget.stringColumn
{ title = "Name"
, value = .name
, toString = identity
, width = Element.fill
}
]
, asc = True
, sortBy = "Id"
, onChange = always idle
}
)
, ( "Name column"
, Widget.sortTable style.sortTable
{ content =
[ { id = 1, name = "Antonio", rating = 2.456, hash = Nothing }
, { id = 2, name = "Ana", rating = 1.34, hash = Just "45jf" }
]
, columns =
[ Widget.stringColumn
{ title = "Name"
, value = .name
, toString = identity
, width = Element.fill
}
, Widget.floatColumn
{ title = "Rating"
, value = .rating
, toString = String.fromFloat
, width = Element.fill
}
]
, asc = True
, sortBy = "Name"
, onChange = always idle
}
)
, ( "Float column"
, Widget.sortTable style.sortTable
{ content =
[ { id = 1, name = "Antonio", rating = 2.456, hash = Nothing }
, { id = 2, name = "Ana", rating = 1.34, hash = Just "45jf" }
]
, columns =
[ Widget.floatColumn
{ title = "Rating"
, value = .rating
, toString = String.fromFloat
, width = Element.fill
}
, Widget.unsortableColumn
{ title = "Hash"
, toString = .hash >> Maybe.withDefault "None"
, width = Element.fill
}
]
, asc = False
, sortBy = "Rating"
, onChange = always idle
}
)
, ( "Unsortable column"
, Widget.sortTable style.sortTable
{ content =
[ { id = 1, name = "Antonio", rating = 2.456, hash = Nothing }
, { id = 2, name = "Ana", rating = 1.34, hash = Just "45jf" }
]
, columns =
[ Widget.floatColumn
{ title = "Rating"
, value = .rating
, toString = String.fromFloat
, width = Element.fill
}
, Widget.unsortableColumn
{ title = "Hash"
, toString = .hash >> Maybe.withDefault "None"
, width = Element.fill
}
]
, asc = True
, sortBy = "Hash"
, onChange = always idle
}
)
, ( "Empty Table"
, Widget.sortTable style.sortTable
{ content =
[ { id = 1, name = "Antonio", rating = 2.456, hash = Nothing }
, { id = 2, name = "Ana", rating = 1.34, hash = Just "45jf" }
]
, columns = []
, asc = True
, sortBy = ""
, onChange = always idle
}
)
]
modal : msg -> Style msg -> List ( String, Element msg )
modal _ _ =
[]
dialog : msg -> Style msg -> List ( String, Element msg )
dialog _ _ =
[]
textInput : msg -> Style msg -> List ( String, Element msg )
textInput idle style =
[ ( "Nothing Selected"
, { chips = []
, text = ""
, placeholder = Nothing
, label = "Label"
, onChange = always idle
}
|> Widget.textInput style.textInput
)
, ( "Some chips"
, { chips =
[ { icon = Icons.triangle |> Element.html |> Element.el []
, text = "A"
, onPress = Just idle
}
, { icon = Icons.circle |> Element.html |> Element.el []
, text = "B"
, onPress = Just idle
}
]
, text = ""
, placeholder = Nothing
, label = "Label"
, onChange = always idle
}
|> Widget.textInput style.textInput
)
]
list : msg -> Style msg -> List ( String, Element msg )
list _ style =
[ ( "Row"
, [ Element.text "A"
, Element.text "B"
, Element.text "C"
]
|> Widget.row style.row
)
, ( "Column"
, [ Element.text "A"
, Element.text "B"
, Element.text "C"
]
|> Widget.column style.cardColumn
)
, ( "Singleton List"
, [ Element.text "A"
]
|> Widget.column style.cardColumn
)
, ( "Empty List"
, []
|> Widget.column style.cardColumn
)
]

View File

@ -33,7 +33,7 @@ iconButton style { onPress, text, icon } =
style.ifDisabled
else
[]
style.otherwise
)
++ [ Region.description text ]
)
@ -63,7 +63,7 @@ button style { onPress, text, icon } =
style.ifDisabled
else
[]
style.otherwise
)
)
{ onPress = onPress

View File

@ -11,7 +11,7 @@ internal :
| element : List (Attribute msg)
, ifFirst : List (Attribute msg)
, ifLast : List (Attribute msg)
, ifCenter : List (Attribute msg)
, otherwise : List (Attribute msg)
}
-> List (Element msg)
-> List (Element msg)
@ -31,7 +31,7 @@ internal style list =
style.ifLast
else
style.ifCenter
style.otherwise
)
)
@ -52,7 +52,7 @@ internalButton :
| element : List (Attribute msg)
, ifFirst : List (Attribute msg)
, ifLast : List (Attribute msg)
, ifCenter : List (Attribute msg)
, otherwise : List (Attribute msg)
}
, button : ButtonStyle msg
}
@ -76,7 +76,7 @@ internalButton style list =
style.list.ifLast
else
style.list.ifCenter
style.list.otherwise
)
, labelRow =
style.button.labelRow
@ -84,6 +84,8 @@ internalButton style list =
style.button.ifDisabled
, ifActive =
style.button.ifActive
, otherwise =
style.button.otherwise
}
)

View File

@ -5,8 +5,8 @@ module Widget exposing
, ExpansionPanel, expansionPanel
, row, column, buttonRow, buttonColumn
, ColumnType, sortTable, floatColumn, intColumn, stringColumn, unsortableColumn
, TextInputStyle, textInput, carousel, tab
, Tab
, TextInputStyle, textInput
, Tab, tab
)
{-| This module contains functions for displaying data.
@ -27,7 +27,7 @@ module Widget exposing
@docs Dialog, modal, dialog
# ExpansionPanel
# Expansion Panel
@docs ExpansionPanel, expansionPanel
@ -37,18 +37,22 @@ module Widget exposing
@docs row, column, buttonRow, buttonColumn
# SortTable
# Sort Table
@docs ColumnType, sortTable, floatColumn, intColumn, stringColumn, unsortableColumn
# Other Widgets
# Text Input
@docs TextInputStyle, textInput, carousel, tab
@docs TextInputStyle, textInput
# Tab
@docs Tab, tab
-}
import Array exposing (Array)
import Element exposing (Attribute, Element, Length)
import Element.Input exposing (Placeholder)
import Internal.Button as Button
@ -57,6 +61,7 @@ import Internal.ExpansionPanel as ExpansionPanel
import Internal.List as List
import Internal.Select as Select
import Internal.SortTable as SortTable
import Internal.Tab as Tab
import Internal.TextInput as TextInput
import Set exposing (Set)
import Widget.Style exposing (ButtonStyle, ColumnStyle, DialogStyle, ExpansionPanelStyle, RowStyle, SortTableStyle, TabStyle)
@ -417,7 +422,7 @@ sortTable =
{----------------------------------------------------------
- OTHER STATELESS WIDGETS
- TAB
----------------------------------------------------------}
@ -436,42 +441,5 @@ tab :
, content : Maybe Int -> Element msg
}
-> Element msg
tab style { tabs, content } =
[ tabs
|> select
|> List.map (selectButton style.button)
|> Element.row style.optionRow
, tabs.selected
|> content
|> Element.el style.content
]
|> Element.column style.containerColumn
{-| A Carousel circles through a non empty list of contents.
-}
carousel :
{ content : ( a, Array a )
, current : Int
, label : a -> Element msg
}
-> Element msg
carousel { content, current, label } =
let
( head, tail ) =
content
in
(if current <= 0 then
head
else if current > Array.length tail then
tail
|> Array.get (Array.length tail - 1)
|> Maybe.withDefault head
else
tail
|> Array.get (current - 1)
|> Maybe.withDefault head
)
|> label
tab =
Tab.tab

View File

@ -1,4 +1,4 @@
module Layout exposing (Layout, Part(..), activate, init, queueMessage, timePassed, view)
module Widget.Layout exposing (Layout, Part(..), activate, init, queueMessage, timePassed, view)
import Array
import Element exposing (Attribute, DeviceClass(..), Element)

View File

@ -9,6 +9,7 @@ type alias ButtonStyle msg =
, labelRow : List (Attribute msg)
, ifDisabled : List (Attribute msg)
, ifActive : List (Attribute msg)
, otherwise : List (Attribute msg)
}
@ -59,7 +60,7 @@ type alias RowStyle msg =
, element : List (Attribute msg)
, ifFirst : List (Attribute msg)
, ifLast : List (Attribute msg)
, ifCenter : List (Attribute msg)
, otherwise : List (Attribute msg)
}
@ -68,7 +69,7 @@ type alias ColumnStyle msg =
, element : List (Attribute msg)
, ifFirst : List (Attribute msg)
, ifLast : List (Attribute msg)
, ifCenter : List (Attribute msg)
, otherwise : List (Attribute msg)
}