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

View File

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

View File

@ -3,10 +3,15 @@ module Data.Example exposing (Model, Msg, init, subscriptions, toCardList, updat
import Data.Style exposing (Style) import Data.Style exposing (Style)
import Element exposing (Element) import Element exposing (Element)
import Example.Button as Button import Example.Button as Button
import Example.Dialog as Dialog
import Example.ExpansionPanel as ExpansionPanel import Example.ExpansionPanel as ExpansionPanel
import Example.List as List
import Example.Modal as Modal
import Example.MultiSelect as MultiSelect import Example.MultiSelect as MultiSelect
import Example.Select as Select import Example.Select as Select
import Example.SortTable as SortTable
import Example.Tab as Tab import Example.Tab as Tab
import Example.TextInput as TextInput
import Framework.Grid as Grid import Framework.Grid as Grid
import View.Test as Test import View.Test as Test
@ -17,6 +22,11 @@ type Msg
| MultiSelect MultiSelect.Msg | MultiSelect MultiSelect.Msg
| ExpansionPanel ExpansionPanel.Msg | ExpansionPanel ExpansionPanel.Msg
| Tab Tab.Msg | Tab Tab.Msg
| SortTable SortTable.Msg
| Modal Modal.Msg
| Dialog Dialog.Msg
| TextInput TextInput.Msg
| List List.Msg
type alias Model = type alias Model =
@ -25,6 +35,34 @@ type alias Model =
, multiSelect : MultiSelect.Model , multiSelect : MultiSelect.Model
, expansionPanel : ExpansionPanel.Model , expansionPanel : ExpansionPanel.Model
, tab : Tab.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 ) = ( tabModel, tabMsg ) =
Tab.init Tab.init
( sortTableModel, sortTableMsg ) =
SortTable.init
( modalModel, modalMsg ) =
Modal.init
( dialogModel, dialogMsg ) =
Dialog.init
( textInputModel, textInputMsg ) =
TextInput.init
( listModel, listMsg ) =
List.init
in in
( { button = buttonModel ( { button = buttonModel
, select = selectModel , select = selectModel
, multiSelect = multiSelectModel , multiSelect = multiSelectModel
, expansionPanel = expansionPanelModel , expansionPanel = expansionPanelModel
, tab = tabModel , tab = tabModel
, sortTable = sortTableModel
, modal = modalModel
, dialog = dialogModel
, textInput = textInputModel
, list = listModel
} }
, [ Cmd.map Button buttonMsg , [ Cmd.map Button buttonMsg
, Cmd.map Select selectMsg , Cmd.map Select selectMsg
, Cmd.map MultiSelect multiSelectMsg , Cmd.map MultiSelect multiSelectMsg
, Cmd.map ExpansionPanel expansionPanelMsg
, Cmd.map Tab tabMsg , 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 |> 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 -> ( Model, Cmd Msg )
update msg model = update msg model =
case msg of (case msg of
Button buttonMsg -> Button m ->
Button.update buttonMsg model.button updateField .button m
|> Tuple.mapBoth
(\a -> { model | button = a })
(Cmd.map Button)
Select selectMsg -> Select m ->
Select.update selectMsg model.select updateField .select m
|> Tuple.mapBoth
(\a -> { model | select = a })
(Cmd.map Select)
MultiSelect multiSelectMsg -> MultiSelect m ->
MultiSelect.update multiSelectMsg model.multiSelect updateField .multiSelect m
|> Tuple.mapBoth
(\a -> { model | multiSelect = a })
(Cmd.map MultiSelect)
ExpansionPanel expansionPanelMsg -> ExpansionPanel m ->
ExpansionPanel.update expansionPanelMsg model.expansionPanel updateField .expansionPanel m
|> Tuple.mapBoth
(\a -> { model | expansionPanel = a })
(Cmd.map ExpansionPanel)
Tab tabMsg -> Tab m ->
Tab.update tabMsg model.tab updateField .tab m
|> Tuple.mapBoth
(\a -> { model | tab = a }) SortTable m ->
(Cmd.map Tab) 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 -> Sub Msg
subscriptions model = subscriptions model =
[ Button.subscriptions model.button |> Sub.map Button let
, Select.subscriptions model.select |> Sub.map Select subFun { from, msgMapper, subscriptionsFun } =
, MultiSelect.subscriptions model.multiSelect |> Sub.map MultiSelect subscriptionsFun (from model) |> Sub.map msgMapper
, ExpansionPanel.subscriptions model.expansionPanel |> Sub.map ExpansionPanel in
, Tab.subscriptions model.tab |> Sub.map Tab [ 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 |> Sub.batch
@ -116,33 +266,33 @@ view :
, multiSelect : Element msg , multiSelect : Element msg
, expansionPanel : Element msg , expansionPanel : Element msg
, tab : Element msg , tab : Element msg
, sortTable : Element msg
, modal : Element msg
, dialog : Element msg
, textInput : Element msg
, list : Element msg
} }
view msgMapper style model = view msgMapper style model =
{ button = { button =
Button.view Button.view (Button >> msgMapper) style (.button model)
(Button >> msgMapper)
style
model.button
, select = , select =
Select.view Select.view (Select >> msgMapper) style (.select model)
(Select >> msgMapper)
style
model.select
, multiSelect = , multiSelect =
MultiSelect.view MultiSelect.view (MultiSelect >> msgMapper) style (.multiSelect model)
(MultiSelect >> msgMapper)
style
model.multiSelect
, expansionPanel = , expansionPanel =
ExpansionPanel.view ExpansionPanel.view (ExpansionPanel >> msgMapper) style (.expansionPanel model)
(ExpansionPanel >> msgMapper)
style
model.expansionPanel
, tab = , tab =
Tab.view Tab.view (Tab >> msgMapper) style (.tab model)
(Tab >> msgMapper) , sortTable =
style SortTable.view (SortTable >> msgMapper) style (.sortTable model)
model.tab , 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 ) -> List ( String, Element msg, Element msg )
toCardList { idle, msgMapper, style, model } = toCardList { idle, msgMapper, style, model } =
[ { title = "Icon Button" [ { title = "Button"
, example = .button , example = .button
, test = Test.iconButton , test = Test.button
} }
, { title = "Select" , { title = "Select"
, example = .select , example = .select
@ -174,7 +324,28 @@ toCardList { idle, msgMapper, style, model } =
, example = .tab , example = .tab
, test = Test.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 |> List.map
(\{ title, example, test } -> (\{ title, example, test } ->
( title ( title
@ -182,6 +353,39 @@ toCardList { idle, msgMapper, style, model } =
|> view msgMapper style |> view msgMapper style
|> example |> example
, test idle style , 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) module Data.Style exposing (Style)
import Element exposing (Attribute) import Widget.Style
import Widget.Style exposing (ButtonStyle, DialogStyle, ExpansionPanelStyle, exposing
SnackbarStyle ,RowStyle,ColumnStyle,TextInputStyle,TabStyle) ( ButtonStyle
, ColumnStyle
, DialogStyle
, ExpansionPanelStyle
, RowStyle
, SortTableStyle
, TabStyle
, TextInputStyle
)
type alias Style msg = type alias Style msg =
Widget.Style.Style Widget.Style.Style
@ -16,5 +25,6 @@ type alias Style msg =
, row : RowStyle msg , row : RowStyle msg
, column : ColumnStyle msg , column : ColumnStyle msg
, cardColumn : ColumnStyle msg , cardColumn : ColumnStyle msg
, sortTable : SortTableStyle msg
} }
msg msg

View File

@ -1,9 +1,9 @@
module Data.Style.ElmUiFramework exposing (style) module Data.Style.ElmUiFramework exposing (style)
import Element exposing (Attribute) import Data.Style exposing (Style)
import Element
import Element.Border as Border import Element.Border as Border
import Element.Font as Font 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
@ -11,12 +11,21 @@ import Framework.Color as Color
import Framework.Grid as Grid import Framework.Grid as Grid
import Framework.Group as Group import Framework.Group as Group
import Framework.Heading as Heading import Framework.Heading as Heading
import Framework.Input as Input
import Framework.Tag as Tag import Framework.Tag as Tag
import Icons import Icons
import Data.Style exposing (Style) import Widget.Style
import Widget.Style exposing (ButtonStyle, DialogStyle, ExpansionPanelStyle, exposing
SnackbarStyle ,RowStyle,ColumnStyle,TextInputStyle,TabStyle) ( ButtonStyle
, ColumnStyle
, DialogStyle
, ExpansionPanelStyle
, RowStyle
, SnackbarStyle
, SortTableStyle
, TabStyle
, TextInputStyle
)
textButton : ButtonStyle msg textButton : ButtonStyle msg
textButton = textButton =
@ -24,6 +33,7 @@ textButton =
, labelRow = Grid.simple , labelRow = Grid.simple
, ifDisabled = Color.disabled , ifDisabled = Color.disabled
, ifActive = Color.primary , ifActive = Color.primary
, otherwise = []
} }
@ -33,6 +43,7 @@ simpleButton =
, labelRow = Grid.simple , labelRow = Grid.simple
, ifDisabled = Color.disabled , ifDisabled = Color.disabled
, ifActive = Color.primary , ifActive = Color.primary
, otherwise = []
} }
@ -57,6 +68,7 @@ menuTabButton =
, labelRow = Grid.simple , labelRow = Grid.simple
, ifDisabled = Color.disabled , ifDisabled = Color.disabled
, ifActive = [ Border.color Color.turquoise ] , ifActive = [ Border.color Color.turquoise ]
, otherwise = []
} }
@ -66,6 +78,7 @@ menuButton =
, container = Button.simple ++ Group.center ++ Color.dark , container = Button.simple ++ Group.center ++ Color.dark
, ifDisabled = Color.disabled , ifDisabled = Color.disabled
, ifActive = Color.primary , ifActive = Color.primary
, otherwise = []
} }
@ -79,6 +92,7 @@ sheetButton =
, labelRow = Grid.simple , labelRow = Grid.simple
, ifDisabled = Color.disabled , ifDisabled = Color.disabled
, ifActive = Color.primary , ifActive = Color.primary
, otherwise = []
} }
@ -88,6 +102,7 @@ buttonStyle =
, container = Button.simple , container = Button.simple
, ifDisabled = Color.disabled , ifDisabled = Color.disabled
, ifActive = Color.primary , ifActive = Color.primary
, otherwise = []
} }
@ -97,6 +112,7 @@ snackbarButton =
, container = Button.simple ++ Color.dark , container = Button.simple ++ Color.dark
, ifDisabled = Color.disabled , ifDisabled = Color.disabled
, ifActive = Color.primary , ifActive = Color.primary
, otherwise = []
} }
@ -106,8 +122,10 @@ tabButtonStyle =
, container = Button.simple ++ Group.top , container = Button.simple ++ Group.top
, ifDisabled = Color.disabled , ifDisabled = Color.disabled
, ifActive = Color.primary , ifActive = Color.primary
, otherwise = []
} }
textInputStyle : TextInputStyle msg textInputStyle : TextInputStyle msg
textInputStyle = textInputStyle =
{ chipButton = chipButtonStyle { chipButton = chipButtonStyle
@ -143,41 +161,43 @@ chipButtonStyle =
, ifDisabled = [] , ifDisabled = []
, labelRow = Grid.simple , labelRow = Grid.simple
, ifActive = Color.primary , ifActive = Color.primary
, otherwise = []
} }
expansionPanelStyle : ExpansionPanelStyle msg expansionPanelStyle : ExpansionPanelStyle msg
expansionPanelStyle = expansionPanelStyle =
{ containerColumn = Card.simple ++ Grid.simple ++ [Element.height <| Element.shrink] { containerColumn = Card.simple ++ Grid.simple ++ [ Element.height <| Element.shrink ]
, panelRow = Grid.spacedEvenly ++ [Element.height <| Element.shrink] , panelRow = Grid.spacedEvenly ++ [ Element.height <| Element.shrink ]
, labelRow = Grid.simple ++ [Element.height <| Element.shrink] , labelRow = Grid.simple ++ [ Element.height <| Element.shrink ]
, content = [] , content = []
, expandIcon = Icons.chevronDown |> Element.html |> Element.el [] , expandIcon = Icons.chevronDown |> Element.html |> Element.el []
, collapseIcon = Icons.chevronUp |> Element.html |> Element.el [] , collapseIcon = Icons.chevronUp |> Element.html |> Element.el []
} }
dialog : DialogStyle msg dialog : DialogStyle msg
dialog = dialog =
{ containerColumn = { containerColumn =
Card.simple Card.simple
++ Grid.simple ++ Grid.simple
++ [ Element.centerY ++ [ Element.centerY
, Element.width <| Element.minimum 280 <| Element.maximum 560 <| Element.fill , Element.width <| Element.minimum 280 <| Element.maximum 560 <| Element.fill
] ]
, title = Heading.h3 , title = Heading.h3
, buttonRow = , buttonRow =
Grid.simple Grid.simple
++ [ Element.paddingEach ++ [ Element.paddingEach
{ top = 28 { top = 28
, bottom = 0 , bottom = 0
, left = 0 , left = 0
, right = 0 , right = 0
} }
] ]
, acceptButton = simpleButton , acceptButton = simpleButton
, dismissButton = textButton , dismissButton = textButton
} }
snackbar : SnackbarStyle msg snackbar : SnackbarStyle msg
snackbar = snackbar =
@ -186,19 +206,21 @@ snackbar =
++ Color.dark ++ Color.dark
++ Grid.simple ++ Grid.simple
++ [ Element.paddingXY 8 6 ++ [ Element.paddingXY 8 6
, Element.height <| Element.px <| 54 , Element.height <| Element.px <| 54
] ]
, button = snackbarButton , button = snackbarButton
, text = [ Element.paddingXY 8 0 ] , text = [ Element.paddingXY 8 0 ]
} }
tab : TabStyle msg tab : TabStyle msg
tab = tab =
{ button = tabButtonStyle { button = tabButtonStyle
, optionRow = Grid.simple , optionRow = Grid.simple
, containerColumn = Grid.compact , containerColumn = Grid.compact
, content = (Card.small ++ Group.bottom) , content = Card.small ++ Group.bottom
} }
row : RowStyle msg row : RowStyle msg
row = row =
@ -206,30 +228,44 @@ row =
, element = [] , element = []
, ifFirst = Group.left , ifFirst = Group.left
, ifLast = Group.right , ifLast = Group.right
, ifCenter = Group.center , otherwise = Group.center
} }
cardColumn : ColumnStyle msg cardColumn : ColumnStyle msg
cardColumn = cardColumn =
{ containerColumn = Grid.compact ++ [Element.height <| Element.fill] { containerColumn = Grid.compact ++ [ Element.height <| Element.fill ]
, element = Card.large ++ [Element.height <| Element.fill] , element = Card.large ++ [ Element.height <| Element.fill ]
, ifFirst = Group.top , ifFirst = Group.top
, ifLast = Group.bottom , ifLast = Group.bottom
, ifCenter = Group.center , otherwise = Group.center
} }
column : ColumnStyle msg column : ColumnStyle msg
column = column =
{ containerColumn = Grid.compact { containerColumn = Grid.compact
, element = [] , element = []
, ifFirst = Group.top , ifFirst = Group.top
, ifLast = Group.bottom , 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 : Style msg
style = style =
{ row = row { sortTable = sortTable
, row = row
, cardColumn = cardColumn , cardColumn = cardColumn
, column = column , column = column
, button = buttonStyle , 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) module Data.Style.Template exposing (style)
import Data.Style 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.Border as Border
import Element.Font as Font import Element.Font as Font
import Element.Background as Background import Widget.Style
import Widget.Style exposing (ButtonStyle, DialogStyle, ExpansionPanelStyle, exposing
SnackbarStyle ,TextInputStyle,TabStyle,ColumnStyle,RowStyle) ( ButtonStyle
, ColumnStyle
, DialogStyle
, ExpansionPanelStyle
, RowStyle
, SnackbarStyle
, TabStyle
, TextInputStyle
,SortTableStyle
)
fontSize : Int fontSize : Int
fontSize = 10 fontSize =
10
box : String -> List (Attribute msg) box : String -> List (Attribute msg)
box string = box string =
@ -18,15 +30,16 @@ box string =
, Background.color <| Element.rgba 1 1 1 0.5 , Background.color <| Element.rgba 1 1 1 0.5
, Element.padding 10 , Element.padding 10
, Element.spacing 10 , Element.spacing 10
, Element.above <| , Element.above <|
Element.el [Font.size <| fontSize] <| Element.el [ Font.size <| fontSize ] <|
Element.text string Element.text string
] ]
decoration : String -> List (Attribute msg) decoration : String -> List (Attribute msg)
decoration string = decoration string =
[ Element.below <| [ Element.below <|
Element.el [Font.size <| fontSize] <| Element.el [ Font.size <| fontSize ] <|
Element.text string Element.text string
, Background.color <| Element.rgb 0.66 0.66 0.66 , Background.color <| Element.rgb 0.66 0.66 0.66
] ]
@ -35,15 +48,16 @@ decoration string =
icon : String -> Element msg icon : String -> Element msg
icon string = icon string =
Element.none Element.none
|> Element.el |> Element.el
[ Element.width <| Element.px 12 [ Element.width <| Element.px 12
, Element.height <| Element.px 12 , Element.height <| Element.px 12
, Border.rounded 6 , Border.rounded 6
, Border.width 1 , Border.width 1
, Element.above <| , Element.above <|
Element.el [Font.size <| fontSize] <| Element.el [ Font.size <| fontSize ] <|
Element.text string Element.text string
] ]
button : String -> ButtonStyle msg button : String -> ButtonStyle msg
button string = button string =
@ -51,8 +65,10 @@ button string =
, labelRow = box <| string ++ ":labelRow" , labelRow = box <| string ++ ":labelRow"
, ifDisabled = decoration <| string ++ ":ifDisabled" , ifDisabled = decoration <| string ++ ":ifDisabled"
, ifActive = decoration <| string ++ ":ifActive" , ifActive = decoration <| string ++ ":ifActive"
, otherwise = decoration <| string ++ ":otherwise"
} }
snackbar : String -> SnackbarStyle msg snackbar : String -> SnackbarStyle msg
snackbar string = snackbar string =
{ containerRow = box <| string ++ ":containerRow" { containerRow = box <| string ++ ":containerRow"
@ -60,15 +76,17 @@ snackbar string =
, text = box <| string ++ ":text" , text = box <| string ++ ":text"
} }
dialog : String -> DialogStyle msg dialog : String -> DialogStyle msg
dialog string = dialog string =
{ containerColumn = box <| string ++ ":containerColumn" { containerColumn = box <| string ++ ":containerColumn"
, title = box <| string ++ ":title" , title = box <| string ++ ":title"
, buttonRow = box <| string ++ ":buttonRow" , buttonRow = box <| string ++ ":buttonRow"
, acceptButton = button <| string ++ ":acceptButton" , acceptButton = button <| string ++ ":acceptButton"
, dismissButton = button <| string ++ ":dismissButton" , dismissButton = button <| string ++ ":dismissButton"
} }
expansionPanel : String -> ExpansionPanelStyle msg expansionPanel : String -> ExpansionPanelStyle msg
expansionPanel string = expansionPanel string =
{ containerColumn = box <| string ++ ":containerColumn" { containerColumn = box <| string ++ ":containerColumn"
@ -79,6 +97,7 @@ expansionPanel string =
, collapseIcon = icon <| string ++ ":collapseIcon" , collapseIcon = icon <| string ++ ":collapseIcon"
} }
textInput : String -> TextInputStyle msg textInput : String -> TextInputStyle msg
textInput string = textInput string =
{ chipButton = button <| string ++ ":chipButton" { chipButton = button <| string ++ ":chipButton"
@ -87,6 +106,7 @@ textInput string =
, input = box <| string ++ ":input" , input = box <| string ++ ":input"
} }
tab : String -> TabStyle msg tab : String -> TabStyle msg
tab string = tab string =
{ button = button <| string ++ ":button" { button = button <| string ++ ":button"
@ -95,27 +115,41 @@ tab string =
, content = box <| string ++ ":content" , content = box <| string ++ ":content"
} }
row : String -> RowStyle msg row : String -> RowStyle msg
row string = row string =
{ containerRow = box <| string ++ ":containerRow" { containerRow = box <| string ++ ":containerRow"
, element = box <| string ++ ":element" , element = box <| string ++ ":element"
, ifFirst = box <| string ++ ":ifFirst" , ifFirst = box <| string ++ ":ifFirst"
, ifLast = box <| string ++ ":ifLast" , ifLast = box <| string ++ ":ifLast"
, ifCenter = box <| string ++ ":ifCenter" , otherwise = box <| string ++ ":otherwise"
} }
column : String -> ColumnStyle msg column : String -> ColumnStyle msg
column string = column string =
{ containerColumn = box <| string ++ ":containerColumn" { containerColumn = box <| string ++ ":containerColumn"
, element = box <| string ++ ":element" , element = box <| string ++ ":element"
, ifFirst = box <| string ++ ":ifFirst" , ifFirst = box <| string ++ ":ifFirst"
, ifLast = box <| string ++ ":ifLast" , 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 = style =
{ row = row <| "row" { sortTable = sortTable <| "sortTable"
, row = row <| "row"
, cardColumn = column <| "cardRow" , cardColumn = column <| "cardRow"
, column = column <| "column" , column = column <| "column"
, button = button <| "button" , button = button <| "button"
@ -139,4 +173,4 @@ style =
, searchIcon = icon "searchIcon" , searchIcon = icon "searchIcon"
, search = box "search" , search = box "search"
, searchFill = box "searchFill" , 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 exposing (Style)
import Data.Style.ElmUiFramework import Data.Style.ElmUiFramework
import Data.Style.Material
import Data.Style.Template import Data.Style.Template
type Theme =
ElmUiFramework type Theme
= ElmUiFramework
| Template | Template
| Material
toStyle : Theme -> Style msg toStyle : Theme -> Style msg
toStyle theme = toStyle theme =
case theme of case theme of
ElmUiFramework -> ElmUiFramework ->
Data.Style.ElmUiFramework.style Data.Style.ElmUiFramework.style
Template -> Template ->
Data.Style.Template.style 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 Element exposing (Element)
import FeatherIcons import FeatherIcons
import Widget import Widget
import Widget.Style exposing (ButtonStyle) import Widget.Style exposing (ButtonStyle, RowStyle)
type alias Style style msg = type alias Style style msg =
{ style { style
| primaryButton : ButtonStyle msg | primaryButton : ButtonStyle msg
, button : ButtonStyle msg , button : ButtonStyle msg
, row : RowStyle msg
} }
type alias Model = type Model
{ isButtonEnabled : Bool = IsButtonEnabled Bool
}
type Msg type Msg
@ -24,17 +24,16 @@ type Msg
init : ( Model, Cmd Msg ) init : ( Model, Cmd Msg )
init = init =
( { isButtonEnabled = True ( IsButtonEnabled True
}
, Cmd.none , Cmd.none
) )
update : Msg -> Model -> ( Model, Cmd Msg ) update : Msg -> Model -> ( Model, Cmd Msg )
update msg model = update msg _ =
case msg of case msg of
ChangedButtonStatus bool -> ChangedButtonStatus bool ->
( { model | isButtonEnabled = bool } ( IsButtonEnabled bool
, Cmd.none , Cmd.none
) )
@ -45,7 +44,7 @@ subscriptions _ =
view : (Msg -> msg) -> Style style msg -> Model -> Element msg view : (Msg -> msg) -> Style style msg -> Model -> Element msg
view msgMapper style model = view msgMapper style (IsButtonEnabled isButtonEnabled) =
[ Widget.button style.primaryButton [ Widget.button style.primaryButton
{ text = "disable me" { text = "disable me"
, icon = , icon =
@ -55,7 +54,7 @@ view msgMapper style model =
|> Element.html |> Element.html
|> Element.el [] |> Element.el []
, onPress = , onPress =
if model.isButtonEnabled then if isButtonEnabled then
ChangedButtonStatus False ChangedButtonStatus False
|> msgMapper |> msgMapper
|> Just |> Just
@ -77,7 +76,4 @@ view msgMapper style model =
|> Just |> Just
} }
] ]
|> Element.row |> Widget.row style.row
[ Element.spaceEvenly
, Element.width <| Element.fill
]

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 = type Model
{ isExpanded : Bool } = IsExpanded Bool
type Msg type Msg
@ -21,18 +21,16 @@ type Msg
init : ( Model, Cmd Msg ) init : ( Model, Cmd Msg )
init = init =
( { isExpanded = False } ( IsExpanded False
, Cmd.none , Cmd.none
) )
update : Msg -> Model -> ( Model, Cmd Msg ) update : Msg -> Model -> ( Model, Cmd Msg )
update msg model = update msg _ =
case msg of case msg of
ToggleCollapsable bool -> ToggleCollapsable bool ->
( { model ( IsExpanded bool
| isExpanded = bool
}
, Cmd.none , Cmd.none
) )
@ -43,9 +41,9 @@ subscriptions _ =
view : (Msg -> msg) -> Style style msg -> Model -> Element msg view : (Msg -> msg) -> Style style msg -> Model -> Element msg
view msgMapper style model = view msgMapper style (IsExpanded isExpanded) =
{ onToggle = ToggleCollapsable >> msgMapper { onToggle = ToggleCollapsable >> msgMapper
, isExpanded = model.isExpanded , isExpanded = isExpanded
, icon = Element.none , icon = Element.none
, text = "Title" , text = "Title"
, content = Element.text <| "Hello World" , 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 = type Model
{ selected : Set Int = Selected (Set Int)
}
type Msg type Msg
@ -24,25 +23,23 @@ type Msg
init : ( Model, Cmd Msg ) init : ( Model, Cmd Msg )
init = init =
( { selected = Set.empty } ( Selected <| Set.empty
, Cmd.none , Cmd.none
) )
update : Msg -> Model -> ( Model, Cmd Msg ) update : Msg -> Model -> ( Model, Cmd Msg )
update msg model = update msg (Selected selected) =
case msg of case msg of
ChangedSelected int -> ChangedSelected int ->
( { model ( selected
| selected = |> (if selected |> Set.member int then
model.selected Set.remove int
|> (if model.selected |> Set.member int then
Set.remove int
else else
Set.insert int Set.insert int
) )
} |> Selected
, Cmd.none , Cmd.none
) )
@ -53,8 +50,8 @@ subscriptions _ =
view : (Msg -> msg) -> Style style msg -> Model -> Element msg view : (Msg -> msg) -> Style style msg -> Model -> Element msg
view msgMapper style model = view msgMapper style (Selected selected) =
{ selected = model.selected { selected = selected
, options = , options =
[ 1, 2, 42 ] [ 1, 2, 42 ]
|> List.map |> List.map

View File

@ -1,7 +1,6 @@
module Example.Select exposing (Model, Msg, init, subscriptions, update, view) module Example.Select exposing (Model, Msg, init, subscriptions, update, view)
import Element exposing (Attribute, Element) import Element exposing (Element)
import FeatherIcons
import Widget import Widget
import Widget.Style exposing (ButtonStyle, RowStyle) import Widget.Style exposing (ButtonStyle, RowStyle)
@ -13,8 +12,8 @@ type alias Style style msg =
} }
type alias Model = type Model
{ selected : Maybe Int } = Selected (Maybe Int)
type Msg type Msg
@ -23,18 +22,16 @@ type Msg
init : ( Model, Cmd Msg ) init : ( Model, Cmd Msg )
init = init =
( { selected = Nothing } ( Selected Nothing
, Cmd.none , Cmd.none
) )
update : Msg -> Model -> ( Model, Cmd Msg ) update : Msg -> Model -> ( Model, Cmd Msg )
update msg model = update msg _ =
case msg of case msg of
ChangedSelected int -> ChangedSelected int ->
( { model ( Selected <| Just int
| selected = Just int
}
, Cmd.none , Cmd.none
) )
@ -45,8 +42,8 @@ subscriptions _ =
view : (Msg -> msg) -> Style style msg -> Model -> Element msg view : (Msg -> msg) -> Style style msg -> Model -> Element msg
view msgMapper style model = view msgMapper style (Selected selected) =
{ selected = model.selected { selected = selected
, options = , options =
[ 1, 2, 42 ] [ 1, 2, 42 ]
|> List.map |> 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 = type Model
{ selected : Maybe Int = Selected (Maybe Int)
}
type Msg type Msg
@ -22,17 +21,16 @@ type Msg
init : ( Model, Cmd Msg ) init : ( Model, Cmd Msg )
init = init =
( { selected = Nothing ( Selected Nothing
}
, Cmd.none , Cmd.none
) )
update : Msg -> Model -> ( Model, Cmd Msg ) update : Msg -> Model -> ( Model, Cmd Msg )
update msg model = update msg _ =
case msg of case msg of
ChangedTab int -> ChangedTab int ->
( { model | selected = Just int } ( Selected <| Just int
, Cmd.none , Cmd.none
) )
@ -43,10 +41,10 @@ subscriptions _ =
view : (Msg -> msg) -> Style style msg -> Model -> Element msg view : (Msg -> msg) -> Style style msg -> Model -> Element msg
view msgMapper style model = view msgMapper style (Selected selected) =
Widget.tab style.tab Widget.tab style.tab
{ tabs = { tabs =
{ selected = model.selected { selected = selected
, options = , options =
[ 1, 2, 3 ] [ 1, 2, 3 ]
|> List.map |> List.map
@ -58,8 +56,8 @@ view msgMapper style model =
, onSelect = ChangedTab >> msgMapper >> Just , onSelect = ChangedTab >> msgMapper >> Just
} }
, content = , content =
\selected -> \s ->
(case selected of (case s of
Just 0 -> Just 0 ->
"This is Tab 1" "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 , chevronDown
, chevronLeft , chevronLeft
, chevronRight , chevronRight
, chevronUp
, circle , circle
, github , github
, menu , menu
, moreVertical , moreVertical
, penTool
, repeat , repeat
, search , search
, slash , slash
, square , square
, triangle , triangle
, chevronUp
, penTool
) )
import Html exposing (Html) import Html exposing (Html)
import Svg exposing (Svg, svg) import Svg exposing (Svg, svg)
import Svg.Attributes exposing (..) import Svg.Attributes as Attributes
svgFeatherIcon : String -> List (Svg msg) -> Html msg svgFeatherIcon : String -> List (Svg msg) -> Html msg
svgFeatherIcon className = svgFeatherIcon className =
svg svg
[ class <| "feather feather-" ++ className [ Attributes.class <| "feather feather-" ++ className
, fill "none" , Attributes.fill "none"
, height "16" , Attributes.height "16"
, stroke "currentColor" , Attributes.stroke "currentColor"
, strokeLinecap "round" , Attributes.strokeLinecap "round"
, strokeLinejoin "round" , Attributes.strokeLinejoin "round"
, strokeWidth "2" , Attributes.strokeWidth "2"
, viewBox "0 0 24 24" , Attributes.viewBox "0 0 24 24"
, width "16" , Attributes.width "16"
] ]
chevronDown : Html msg chevronDown : Html msg
chevronDown = chevronDown =
svgFeatherIcon "chevron-down" 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 : Html msg
chevronRight = chevronRight =
svgFeatherIcon "chevron-right" 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 : Html msg
chevronLeft = chevronLeft =
svgFeatherIcon "chevron-left" 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 : Html msg
chevronUp = chevronUp =
svgFeatherIcon "chevron-up" 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 : Html msg
repeat = repeat =
svgFeatherIcon "repeat" svgFeatherIcon "repeat"
[ Svg.polyline [ points "17 1 21 5 17 9" ] [] [ Svg.polyline [ Attributes.points "17 1 21 5 17 9" ] []
, Svg.path [ d "M3 11V9a4 4 0 0 1 4-4h14" ] [] , Svg.path [ Attributes.d "M3 11V9a4 4 0 0 1 4-4h14" ] []
, Svg.polyline [ points "7 23 3 19 7 15" ] [] , Svg.polyline [ Attributes.points "7 23 3 19 7 15" ] []
, Svg.path [ d "M21 13v2a4 4 0 0 1-4 4H3" ] [] , Svg.path [ Attributes.d "M21 13v2a4 4 0 0 1-4 4H3" ] []
] ]
penTool : Html msg penTool : Html msg
penTool = penTool =
svgFeatherIcon "pen-tool" svgFeatherIcon "pen-tool"
[ Svg.path [ d "M12 19l7-7 3 3-7 7-3-3z" ] [] [ Svg.path [ Attributes.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 [ Attributes.d "M18 13l-1.5-7.5L2 2l3.5 14.5L13 18l5-5z" ] []
, Svg.path [ d "M2 2l7.586 7.586" ] [] , Svg.path [ Attributes.d "M2 2l7.586 7.586" ] []
, Svg.circle [ cx "11", cy "11", r "2" ] [] , Svg.circle
[ Attributes.cx "11"
, Attributes.cy "11"
, Attributes.r "2"
]
[]
] ]
book : Html msg book : Html msg
book = book =
svgFeatherIcon "book" svgFeatherIcon "book"
[ Svg.path [ d "M4 19.5A2.5 2.5 0 0 1 6.5 17H20" ] [] [ Svg.path [ Attributes.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 "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 : Html msg
github = github =
svgFeatherIcon "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 : Html msg
menu = menu =
svgFeatherIcon "menu" svgFeatherIcon "menu"
[ Svg.line [ x1 "3", y1 "12", x2 "21", y2 "12" ] [] [ Svg.line
, Svg.line [ x1 "3", y1 "6", x2 "21", y2 "6" ] [] [ Attributes.x1 "3"
, Svg.line [ x1 "3", y1 "18", x2 "21", y2 "18" ] [] , 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 : Html msg
moreVertical = moreVertical =
svgFeatherIcon "more-vertical" svgFeatherIcon "more-vertical"
[ Svg.circle [ cx "12", cy "12", r "1" ] [] [ Svg.circle [ Attributes.cx "12", Attributes.cy "12", Attributes.r "1" ] []
, Svg.circle [ cx "12", cy "5", r "1" ] [] , Svg.circle [ Attributes.cx "12", Attributes.cy "5", Attributes.r "1" ] []
, Svg.circle [ cx "12", cy "19", r "1" ] [] , Svg.circle [ Attributes.cx "12", Attributes.cy "19", Attributes.r "1" ] []
] ]
circle : Html msg circle : Html msg
circle = circle =
svgFeatherIcon "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 : Html msg
slash = slash =
svgFeatherIcon "slash" svgFeatherIcon "slash"
[ Svg.circle [ cx "12", cy "12", r "10" ] [] [ Svg.circle
, Svg.line [ x1 "4.93", y1 "4.93", x2 "19.07", y2 "19.07" ] [] [ 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 : 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 [ 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 : 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
[ Attributes.x "3"
, Attributes.y "3"
, Attributes.width "18"
, Attributes.height "18"
, Attributes.rx "2"
, Attributes.ry "2"
]
[]
] ]
search : Html msg search : Html msg
search = search =
svgFeatherIcon "search" svgFeatherIcon "search"
[ Svg.circle [ cx "11", cy "11", r "8" ] [] [ Svg.circle
, Svg.line [ x1 "21", y1 "21", x2 "16.65", y2 "16.65" ] [] [ 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.Events as Events
import Browser.Navigation as Navigation import Browser.Navigation as Navigation
import Data.Section as Section exposing (Section(..)) 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 Data.Theme as Theme exposing (Theme(..))
import Element exposing (Attribute, DeviceClass(..), Element) import Element exposing (DeviceClass(..))
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.Card as Card
import Framework.Color as Color
import Framework.Grid as Grid import Framework.Grid as Grid
import Framework.Group as Group
import Framework.Heading as Heading import Framework.Heading as Heading
import Framework.Input as Input
import Framework.Tag as Tag
import Html exposing (Html) import Html exposing (Html)
import Html.Attributes as Attributes
import Icons import Icons
import Layout exposing (Layout, Part)
import Reusable import Reusable
import Set exposing (Set)
import Stateless import Stateless
import Task import Task
import Time import Time
import Widget import Widget
import Widget.Layout as Layout exposing (Layout, Part)
import Widget.ScrollingNav as ScrollingNav import Widget.ScrollingNav as ScrollingNav
import Widget.Snackbar as Snackbar
import Widget.Style exposing (ButtonStyle)
type alias LoadedModel = type alias LoadedModel =
@ -41,7 +28,10 @@ type alias LoadedModel =
, scrollingNav : ScrollingNav.Model Section , scrollingNav : ScrollingNav.Model Section
, layout : Layout LoadedMsg , layout : Layout LoadedMsg
, displayDialog : Bool , displayDialog : Bool
, window : { height : Int, width : Int } , window :
{ height : Int
, width : Int
}
, search : , search :
{ raw : String { raw : String
, current : String , current : String
@ -110,7 +100,7 @@ initialModel { viewport } =
, current = "" , current = ""
, remaining = 0 , remaining = 0
} }
, theme = ElmUiFramework , theme = Material
} }
, [ cmd , [ cmd
, statelessCmd |> Cmd.map StatelessSpecific , statelessCmd |> Cmd.map StatelessSpecific
@ -171,17 +161,17 @@ view model =
(\section -> (\section ->
(case section of (case section of
ReusableViews -> ReusableViews ->
Reusable.view m.theme Reusable.view
{ addSnackbar = AddSnackbar { theme = m.theme
, addSnackbar = AddSnackbar
} }
StatelessViews -> StatelessViews ->
Stateless.view m.theme Stateless.view
{ msgMapper = StatelessSpecific { theme = m.theme
, showDialog = ToggleDialog True , msgMapper = StatelessSpecific
, changedSheet = ChangedSidebar , model = m.stateless
} }
m.stateless
) )
|> (\{ title, description, items } -> |> (\{ title, description, items } ->
[ Element.el Heading.h2 <| Element.text <| title [ Element.el Heading.h2 <| Element.text <| title
@ -213,12 +203,17 @@ view model =
] ]
|> Element.column Grid.simple |> Element.column Grid.simple
, more , more
|> Element.el [ Element.height <| Element.fill ] |> Element.el
[ Element.width <| Element.fill
]
] ]
|> Widget.column style.cardColumn |> Widget.column style.cardColumn
) )
|> 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 ])
) )
@ -266,6 +261,15 @@ view model =
, text = "Template Theme" , text = "Template Theme"
, icon = Icons.penTool |> Element.html |> Element.el [] , 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 , { onPress = Nothing
, text = "Placeholder" , text = "Placeholder"
, icon = Icons.circle |> Element.html |> Element.el [] , icon = Icons.circle |> Element.html |> Element.el []
@ -428,7 +432,7 @@ update msg model =
subscriptions : Model -> Sub Msg subscriptions : Model -> Sub Msg
subscriptions model = subscriptions _ =
Sub.batch Sub.batch
[ Time.every 50 (always (TimePassed 50)) [ Time.every 50 (always (TimePassed 50))
, Events.onResize (\h w -> Resized { height = h, width = w }) , 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.Style exposing (Style)
import Data.Theme as Theme exposing (Theme) import Data.Theme as Theme exposing (Theme)
import Element exposing (Element)
import Framework.Grid as Grid
import Widget
type alias Item = snackbar : Style msg -> (( String, Bool ) -> msg) -> ( String, Element msg, Element msg )
{ name : String
, amount : Int
, price : Float
}
snackbar : Style msg -> (( String, Bool ) -> msg) -> ( String, Element msg,Element msg )
snackbar style addSnackbar = snackbar style addSnackbar =
( "Snackbar" ( "Snackbar"
, [ Widget.button style.button , [ Widget.button style.button
@ -45,7 +18,7 @@ snackbar style addSnackbar =
, False , False
) )
, text = "Add Notification" , text = "Add Notification"
, icon =Element.none , icon = Element.none
} }
, Widget.button style.button , Widget.button style.button
{ onPress = { onPress =
@ -63,11 +36,8 @@ snackbar style addSnackbar =
) )
scrollingNavCard : Style msg -> ( String, Element msg, Element msg ) scrollingNavCard : Style msg -> ( String, Element msg, Element msg )
scrollingNavCard style = scrollingNavCard _ =
( "Scrolling Nav" ( "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
@ -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 : view :
Theme -> { theme : Theme
{ addSnackbar : ( String, Bool ) -> msg , addSnackbar : ( String, Bool ) -> msg
} }
-> ->
{ title : String { title : String
, description : String , description : String
, items : List ( String, Element msg,Element msg ) , items : List ( String, Element msg, Element msg )
} }
view theme { addSnackbar } = view { theme, addSnackbar } =
let let
style = Theme.toStyle theme style =
Theme.toStyle theme
in 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 style addSnackbar [ snackbar style addSnackbar
, scrollingNavCard style , scrollingNavCard style
, layout style
] ]
} }

View File

@ -1,37 +1,19 @@
module Stateless exposing (Model, Msg, init, update, view) module Stateless exposing (Model, Msg, init, update, view)
import Array
import Data.Example as Example import Data.Example as Example
import Data.Style exposing (Style)
import Data.Theme as Theme exposing (Theme) import Data.Theme as Theme exposing (Theme)
import Element exposing (Element) import Element exposing (Element)
import Element.Background as Background import Widget.Layout exposing (Part(..))
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
type alias Model = type alias Model =
{ chipTextInput : Set String { carousel : Int
, carousel : Int
, textInput : String
, table : { title : String, asc : Bool }
, example : Example.Model , example : Example.Model
} }
type Msg type Msg
= ToggleTextInputChip String = ExampleSpecific Example.Msg
| SetCarousel Int
| SetTextInput String
| ChangedSorting String
| ExampleSpecific Example.Msg
| Idle | Idle
@ -41,10 +23,7 @@ init =
( example, cmd ) = ( example, cmd ) =
Example.init Example.init
in in
( { chipTextInput = Set.empty ( { carousel = 0
, carousel = 0
, textInput = ""
, table = { title = "Name", asc = True }
, example = example , example = example
} }
, cmd |> Cmd.map ExampleSpecific , cmd |> Cmd.map ExampleSpecific
@ -63,310 +42,24 @@ update msg model =
, exampleCmd |> Cmd.map ExampleSpecific , 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 -> Idle ->
( model, Cmd.none ) ( 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 : view :
Theme { theme : Theme
-> , msgMapper : Msg -> msg
{ msgMapper : Msg -> msg , model : Model
, showDialog : msg }
, changedSheet : Maybe Part -> msg
}
-> Model
-> ->
{ title : String { title : String
, description : String , description : String
, items : List ( String, Element msg, Element msg ) , items : List ( String, Element msg, Element msg )
} }
view theme { msgMapper, showDialog, changedSheet } model = view { theme, msgMapper, model } =
let let
style = style =
Theme.toStyle theme Theme.toStyle theme
map ( a, b, c ) =
( a
, b |> Element.map msgMapper
, c |> Element.map msgMapper
)
in 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."
@ -377,11 +70,4 @@ view theme { msgMapper, showDialog, changedSheet } model =
, style = style , style = style
, model = model.example , 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.Style exposing (Style)
import Data.Theme as Theme exposing (Theme)
import Element exposing (Element) 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 Icons
import Layout exposing (Part(..)) import Set
import Set exposing (Set)
import Widget import Widget
import Widget.Layout exposing (Part(..))
iconButton : msg -> Style msg -> List (Element msg) button : msg -> Style msg -> List ( String, Element msg )
iconButton idle style = button idle style =
[ Element.row Grid.spacedEvenly [ ( "Button"
[ "Button" , Widget.button style.button
|> Element.text
, Widget.button style.button
{ text = "Button" { text = "Button"
, icon = Icons.triangle |> Element.html |> Element.el [] , icon = Icons.triangle |> Element.html |> Element.el []
, onPress = Just idle , onPress = Just idle
} }
] )
, Element.row Grid.spacedEvenly , ( "Text button"
[ "Text button" , Widget.textButton style.button
|> Element.text
, Widget.textButton style.button
{ text = "Button" { text = "Button"
, onPress = Just idle , onPress = Just idle
} }
] )
, Element.row Grid.spacedEvenly , ( "Icon button"
[ "Icon button" , Widget.iconButton style.button
|> Element.text
, Widget.iconButton style.button
{ text = "Button" { text = "Button"
, icon = Icons.triangle |> Element.html |> Element.el [] , icon = Icons.triangle |> Element.html |> Element.el []
, onPress = Just idle , onPress = Just idle
} }
] )
, Element.row Grid.spacedEvenly , ( "Disabled button"
[ "Disabled button" , Widget.button style.button
|> Element.text
, Widget.button style.button
{ text = "Button" { text = "Button"
, icon = Icons.triangle |> Element.html |> Element.el [] , icon = Icons.triangle |> Element.html |> Element.el []
, onPress = Nothing , onPress = Nothing
} }
] )
, Element.row Grid.spacedEvenly , ( "Inactive Select button"
[ "Inactive Select button" , Widget.selectButton style.button
|> Element.text
, Widget.selectButton style.button
( False ( False
, { text = "Button" , { text = "Button"
, icon = Icons.triangle |> Element.html |> Element.el [] , icon = Icons.triangle |> Element.html |> Element.el []
, onPress = Just idle , onPress = Just idle
} }
) )
] )
, Element.row Grid.spacedEvenly , ( "Active Select button"
[ "Active Select button" , Widget.selectButton style.button
|> Element.text
, Widget.selectButton style.button
( True ( True
, { text = "Button" , { text = "Button"
, icon = Icons.triangle |> Element.html |> Element.el [] , icon = Icons.triangle |> Element.html |> Element.el []
, onPress = Just idle , onPress = Just idle
} }
) )
] )
] ]
select : msg -> Style msg -> List (Element msg) select : msg -> Style msg -> List ( String, Element msg )
select idle style = select idle style =
[ Element.row Grid.spacedEvenly [ ( "First selected"
[ "First selected" , { selected = Just 0
|> Element.text , options =
|> Element.el [ Element.width <| Element.fill ] [ 1, 2, 42 ]
, { selected = Just 0 |> List.map
, options = (\int ->
[ 1, 2, 42 ] { text = String.fromInt int
|> List.map , icon = Element.none
(\int -> }
{ text = String.fromInt int )
, icon = Element.none , onSelect = always idle >> Just
} }
)
, onSelect = always idle >> Just
}
|> Widget.select |> Widget.select
|> Widget.buttonRow |> Widget.buttonRow
{ list = style.row { list = style.row
, button = style.button , button = style.button
} }
] )
, Element.row Grid.spacedEvenly , ( "Nothing selected"
[ "Nothing selected" , { selected = Nothing
|> Element.text , options =
|> Element.el [ Element.width <| Element.fill ] [ 1, 2, 42 ]
, { selected = Nothing |> List.map
, options = (\int ->
[ 1, 2, 42 ] { text = String.fromInt int
|> List.map , icon = Element.none
(\int -> }
{ text = String.fromInt int )
, icon = Element.none , onSelect = always idle >> Just
} }
)
, onSelect = always idle >> Just
}
|> Widget.select |> Widget.select
|> Widget.buttonRow |> Widget.buttonRow
{ list = style.row { list = style.row
, button = style.button , button = style.button
} }
] )
, Element.row Grid.spacedEvenly , ( "Invalid selection"
[ "Invalid selection" , { selected = Just -1
|> Element.text , options =
|> Element.el [ Element.width <| Element.fill ] [ 1, 2, 42 ]
, { selected = Just -1 |> List.map
, options = (\int ->
[ 1, 2, 42 ] { text = String.fromInt int
|> List.map , icon = Element.none
(\int -> }
{ text = String.fromInt int )
, icon = Element.none , onSelect = always idle >> Just
} }
)
, onSelect = always idle >> Just
}
|> Widget.select |> Widget.select
|> Widget.buttonRow |> Widget.buttonRow
{ list = style.row { list = style.row
, button = style.button , button = style.button
} }
] )
, Element.row Grid.spacedEvenly , ( "Disabled selection"
[ "Disabled selection" , { selected = Just 0
|> Element.text , options =
|> Element.el [ Element.width <| Element.fill ] [ 1, 2, 42 ]
, { selected = Just 0 |> List.map
, options = (\int ->
[ 1, 2, 42 ] { text = String.fromInt int
|> List.map , icon = Element.none
(\int -> }
{ text = String.fromInt int )
, icon = Element.none , onSelect = always Nothing
} }
)
, onSelect = always Nothing
}
|> Widget.select |> Widget.select
|> Widget.buttonRow |> Widget.buttonRow
{ list = style.row { list = style.row
, button = style.button , button = style.button
} }
] )
, Element.row Grid.spacedEvenly , ( "Empty Options"
[ "Empty Options" , { selected = Nothing
|> Element.text , options =
|> Element.el [ Element.width <| Element.fill ] []
, { selected = Nothing |> List.map
, options = (\int ->
[] { text = String.fromInt int
|> List.map , icon = Element.none
(\int -> }
{ text = String.fromInt int )
, icon = Element.none , onSelect = always idle >> Just
} }
)
, onSelect = always idle >> Just
}
|> Widget.select |> Widget.select
|> Widget.buttonRow |> Widget.buttonRow
{ list = style.row { list = style.row
, button = style.button , button = style.button
} }
] )
] ]
multiSelect : msg -> Style msg -> List (Element msg) multiSelect : msg -> Style msg -> List ( String, Element msg )
multiSelect idle style = multiSelect idle style =
[ Element.row Grid.spacedEvenly [ ( "Some selected"
[ "Some selected" , { selected = Set.fromList [ 0, 1 ]
|> Element.text , options =
|> Element.el [ Element.width <| Element.fill ] [ 1, 2, 42 ]
, { selected = Set.fromList [ 0, 1 ] |> List.map
, options = (\int ->
[ 1, 2, 42 ] { text = String.fromInt int
|> List.map , icon = Element.none
(\int -> }
{ text = String.fromInt int )
, icon = Element.none , onSelect = always idle >> Just
} }
)
, onSelect = always idle >> Just
}
|> Widget.multiSelect |> Widget.multiSelect
|> Widget.buttonRow |> Widget.buttonRow
{ list = style.row { list = style.row
, button = style.button , button = style.button
} }
] )
, Element.row Grid.spacedEvenly , ( "Nothing selected"
[ "Nothing selected" , { selected = Set.empty
|> Element.text , options =
|> Element.el [ Element.width <| Element.fill ] [ 1, 2, 42 ]
, { selected = Set.empty |> List.map
, options = (\int ->
[ 1, 2, 42 ] { text = String.fromInt int
|> List.map , icon = Element.none
(\int -> }
{ text = String.fromInt int )
, icon = Element.none , onSelect = always idle >> Just
} }
)
, onSelect = always idle >> Just
}
|> Widget.multiSelect |> Widget.multiSelect
|> Widget.buttonRow |> Widget.buttonRow
{ list = style.row { list = style.row
, button = style.button , button = style.button
} }
] )
, Element.row Grid.spacedEvenly , ( "Invalid selection"
[ "Invalid selection" , { selected = Set.singleton -1
|> Element.text , options =
|> Element.el [ Element.width <| Element.fill ] [ 1, 2, 42 ]
, { selected = Set.singleton -1 |> List.map
, options = (\int ->
[ 1, 2, 42 ] { text = String.fromInt int
|> List.map , icon = Element.none
(\int -> }
{ text = String.fromInt int )
, icon = Element.none , onSelect = always idle >> Just
} }
)
, onSelect = always idle >> Just
}
|> Widget.multiSelect |> Widget.multiSelect
|> Widget.buttonRow |> Widget.buttonRow
{ list = style.row { list = style.row
, button = style.button , button = style.button
} }
] )
, Element.row Grid.spacedEvenly , ( "Disabled selection"
[ "Disabled selection" , { selected = Set.singleton 0
|> Element.text , options =
|> Element.el [ Element.width <| Element.fill ] [ 1, 2, 42 ]
, { selected = Set.singleton 0 |> List.map
, options = (\int ->
[ 1, 2, 42 ] { text = String.fromInt int
|> List.map , icon = Element.none
(\int -> }
{ text = String.fromInt int )
, icon = Element.none , onSelect = always Nothing
} }
)
, onSelect = always Nothing
}
|> Widget.multiSelect |> Widget.multiSelect
|> Widget.buttonRow |> Widget.buttonRow
{ list = style.row { list = style.row
, button = style.button , button = style.button
} }
] )
, Element.row Grid.spacedEvenly , ( "Empty Options"
[ "Empty Options" , { selected = Set.empty
|> Element.text , options =
|> Element.el [ Element.width <| Element.fill ] []
, { selected = Set.empty |> List.map
, options = (\int ->
[] { text = String.fromInt int
|> List.map , icon = Element.none
(\int -> }
{ text = String.fromInt int )
, icon = Element.none , onSelect = always idle >> Just
} }
)
, onSelect = always idle >> Just
}
|> Widget.multiSelect |> Widget.multiSelect
|> Widget.buttonRow |> Widget.buttonRow
{ list = style.row { list = style.row
, button = style.button , button = style.button
} }
] )
] ]
expansionPanel : msg -> Style msg -> List (Element msg) expansionPanel : msg -> Style msg -> List ( String, Element msg )
expansionPanel idle style = expansionPanel idle style =
[ Element.row Grid.spacedEvenly [ ( "Collapsed"
[ "Collapsed" , { onToggle = always idle
|> Element.text , isExpanded = False
|> Element.el [ Element.width <| Element.fill ] , icon = Icons.triangle |> Element.html |> Element.el []
, { onToggle = always idle , text = "Button"
, isExpanded = False , content = Element.text <| "Hidden Message"
, icon = Icons.triangle |> Element.html |> Element.el [] }
, text = "Button"
, content = Element.text <| "Hidden Message"
}
|> Widget.expansionPanel style.expansionPanel |> Widget.expansionPanel style.expansionPanel
] )
, Element.row Grid.spacedEvenly , ( "Expanded"
[ "Expanded" , { onToggle = always idle
|> Element.text , isExpanded = True
|> Element.el [ Element.width <| Element.fill ] , icon = Icons.triangle |> Element.html |> Element.el []
, { onToggle = always idle , text = "Button"
, isExpanded = True , content = Element.text <| "Hidden Message"
, icon = Icons.triangle |> Element.html |> Element.el [] }
, text = "Button"
, content = Element.text <| "Hidden Message"
}
|> Widget.expansionPanel style.expansionPanel |> Widget.expansionPanel style.expansionPanel
] )
] ]
tab : msg -> Style msg -> List (Element msg) tab : msg -> Style msg -> List ( String, Element msg )
tab idle style = tab idle style =
[ Element.row Grid.spacedEvenly [ ( "Nothing selected"
[ "Nothing selected" , Widget.tab style.tab
|> Element.text
|> Element.el [ Element.width <| Element.fill ]
, Widget.tab style.tab
{ tabs = { tabs =
{ selected = Nothing { selected = Nothing
, options = , options =
@ -357,12 +298,9 @@ tab idle style =
) )
|> Element.text |> Element.text
} }
] )
, Element.row Grid.spacedEvenly , ( "Tab selected"
[ "Tab selected" , Widget.tab style.tab
|> Element.text
|> Element.el [ Element.width <| Element.fill ]
, Widget.tab style.tab
{ tabs = { tabs =
{ selected = Just 0 { selected = Just 0
, options = , options =
@ -386,5 +324,190 @@ tab idle style =
) )
|> Element.text |> 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 style.ifDisabled
else else
[] style.otherwise
) )
++ [ Region.description text ] ++ [ Region.description text ]
) )
@ -63,7 +63,7 @@ button style { onPress, text, icon } =
style.ifDisabled style.ifDisabled
else else
[] style.otherwise
) )
) )
{ onPress = onPress { onPress = onPress

View File

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

View File

@ -5,8 +5,8 @@ module Widget exposing
, ExpansionPanel, expansionPanel , ExpansionPanel, expansionPanel
, row, column, buttonRow, buttonColumn , row, column, buttonRow, buttonColumn
, ColumnType, sortTable, floatColumn, intColumn, stringColumn, unsortableColumn , ColumnType, sortTable, floatColumn, intColumn, stringColumn, unsortableColumn
, TextInputStyle, textInput, carousel, tab , TextInputStyle, textInput
, Tab , Tab, tab
) )
{-| This module contains functions for displaying data. {-| This module contains functions for displaying data.
@ -27,7 +27,7 @@ module Widget exposing
@docs Dialog, modal, dialog @docs Dialog, modal, dialog
# ExpansionPanel # Expansion Panel
@docs ExpansionPanel, expansionPanel @docs ExpansionPanel, expansionPanel
@ -37,18 +37,22 @@ module Widget exposing
@docs row, column, buttonRow, buttonColumn @docs row, column, buttonRow, buttonColumn
# SortTable # Sort Table
@docs ColumnType, sortTable, floatColumn, intColumn, stringColumn, unsortableColumn @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 exposing (Attribute, Element, Length)
import Element.Input exposing (Placeholder) import Element.Input exposing (Placeholder)
import Internal.Button as Button import Internal.Button as Button
@ -57,6 +61,7 @@ import Internal.ExpansionPanel as ExpansionPanel
import Internal.List as List import Internal.List as List
import Internal.Select as Select import Internal.Select as Select
import Internal.SortTable as SortTable import Internal.SortTable as SortTable
import Internal.Tab as Tab
import Internal.TextInput as TextInput import Internal.TextInput as TextInput
import Set exposing (Set) import Set exposing (Set)
import Widget.Style exposing (ButtonStyle, ColumnStyle, DialogStyle, ExpansionPanelStyle, RowStyle, SortTableStyle, TabStyle) 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 , content : Maybe Int -> Element msg
} }
-> Element msg -> Element msg
tab style { tabs, content } = tab =
[ tabs Tab.tab
|> 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

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 Array
import Element exposing (Attribute, DeviceClass(..), Element) import Element exposing (Attribute, DeviceClass(..), Element)

View File

@ -9,6 +9,7 @@ type alias ButtonStyle msg =
, labelRow : List (Attribute msg) , labelRow : List (Attribute msg)
, ifDisabled : List (Attribute msg) , ifDisabled : List (Attribute msg)
, ifActive : List (Attribute msg) , ifActive : List (Attribute msg)
, otherwise : List (Attribute msg)
} }
@ -59,7 +60,7 @@ type alias RowStyle msg =
, element : List (Attribute msg) , element : List (Attribute msg)
, ifFirst : List (Attribute msg) , ifFirst : List (Attribute msg)
, ifLast : 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) , element : List (Attribute msg)
, ifFirst : List (Attribute msg) , ifFirst : List (Attribute msg)
, ifLast : List (Attribute msg) , ifLast : List (Attribute msg)
, ifCenter : List (Attribute msg) , otherwise : List (Attribute msg)
} }