From 15872d5093c4b372e96cfa36ca3c5ca9baca5dc5 Mon Sep 17 00:00:00 2001 From: Lucas Payr Date: Thu, 21 Jan 2021 14:45:56 +0100 Subject: [PATCH] started work on Icons --- elm.json | 7 +- example/src/Data/Style/Material.elm | 9 +- example/src/Example/Button.elm | 12 +- example/src/Example/Dialog.elm | 7 +- example/src/Example/ExpansionPanel.elm | 2 +- example/src/Example/Icon.elm | 127 +++++++++++ example/src/Example/Modal.elm | 7 +- example/src/Example/MultiSelect.elm | 2 +- example/src/Example/Select.elm | 2 +- example/src/Example/SortTable.elm | 2 +- example/src/Example/Tab.elm | 2 +- example/src/Example/TextInput.elm | 4 +- example/src/Main.elm | 13 +- example/src/Reusable.elm | 4 +- example/src/View/Test.elm | 44 ++-- src/Internal/Button.elm | 24 ++- src/Internal/ExpansionPanel.elm | 15 +- src/Internal/Select.elm | 21 +- src/Widget.elm | 23 +- src/Widget/Icon.elm | 249 ++++++++++++++++++++++ src/Widget/Layout.elm | 4 +- src/Widget/ScrollingNav.elm | 2 +- src/Widget/Style.elm | 38 +++- src/Widget/Style/Material.elm | 278 ++++++++++++++++++++----- 24 files changed, 748 insertions(+), 150 deletions(-) create mode 100644 example/src/Example/Icon.elm diff --git a/elm.json b/elm.json index 703e55a..3a307db 100644 --- a/elm.json +++ b/elm.json @@ -10,10 +10,11 @@ "Widget.Style.Material", "Widget.Style.Material.Typography", "Widget.Style.Material.Color", - "Widget.Style.Template", + "Widget.Style.Customize", "Widget.Layout", "Widget.ScrollingNav", - "Widget.Snackbar" + "Widget.Snackbar", + "Widget.Icon" ], "elm-version": "0.19.0 <= v < 0.20.0", "dependencies": { @@ -33,4 +34,4 @@ "test-dependencies": { "elm-explorations/test": "1.2.1 <= v < 2.0.0" } -} +} \ No newline at end of file diff --git a/example/src/Data/Style/Material.elm b/example/src/Data/Style/Material.elm index c430e74..44a57ed 100644 --- a/example/src/Data/Style/Material.elm +++ b/example/src/Data/Style/Material.elm @@ -24,16 +24,17 @@ import Widget.Style , TextInputStyle ) import Widget.Style.Material as Material exposing (Palette) - +import FeatherIcons +import Widget.Icon as Icon sortTable : Palette -> SortTableStyle msg sortTable palette = { elementTable = [] , content = { header = Material.textButton palette - , ascIcon = Icons.chevronUp |> Element.html |> Element.el [] - , descIcon = Icons.chevronDown |> Element.html |> Element.el [] - , defaultIcon = Element.none + , ascIcon = FeatherIcons.chevronUp |> Icon.elmFeather FeatherIcons.toHtml + , descIcon = FeatherIcons.chevronDown |> Icon.elmFeather FeatherIcons.toHtml + , defaultIcon = always Element.none } } diff --git a/example/src/Example/Button.elm b/example/src/Example/Button.elm index ef8e669..780d5fe 100644 --- a/example/src/Example/Button.elm +++ b/example/src/Example/Button.elm @@ -6,7 +6,7 @@ import FeatherIcons import Widget import Widget.Style exposing (ButtonStyle, RowStyle) import Widget.Style.Material as Material - +import Widget.Icon as Icon type alias Style style msg = { style @@ -61,10 +61,7 @@ view msgMapper style (IsButtonEnabled isButtonEnabled) = { text = "disable me" , icon = FeatherIcons.slash - |> FeatherIcons.withSize 16 - |> FeatherIcons.toHtml [] - |> Element.html - |> Element.el [] + |> Icon.elmFeather FeatherIcons.toHtml , onPress = if isButtonEnabled then ChangedButtonStatus False @@ -78,10 +75,7 @@ view msgMapper style (IsButtonEnabled isButtonEnabled) = { text = "reset" , icon = FeatherIcons.repeat - |> FeatherIcons.withSize 16 - |> FeatherIcons.toHtml [] - |> Element.html - |> Element.el [] + |> Icon.elmFeather FeatherIcons.toHtml , onPress = ChangedButtonStatus True |> msgMapper diff --git a/example/src/Example/Dialog.elm b/example/src/Example/Dialog.elm index 977585b..509886b 100644 --- a/example/src/Example/Dialog.elm +++ b/example/src/Example/Dialog.elm @@ -6,7 +6,7 @@ import FeatherIcons import Widget import Widget.Style exposing (ButtonStyle, DialogStyle) import Widget.Style.Material as Material - +import Widget.Icon as Icon type alias Style style msg = { style @@ -59,10 +59,7 @@ view msgMapper style (IsOpen isOpen) = { text = "show Dialog" , icon = FeatherIcons.eye - |> FeatherIcons.withSize 16 - |> FeatherIcons.toHtml [] - |> Element.html - |> Element.el [] + |> Icon.elmFeather FeatherIcons.toHtml , onPress = OpenDialog True |> msgMapper diff --git a/example/src/Example/ExpansionPanel.elm b/example/src/Example/ExpansionPanel.elm index 5f29fc0..c392eff 100644 --- a/example/src/Example/ExpansionPanel.elm +++ b/example/src/Example/ExpansionPanel.elm @@ -54,7 +54,7 @@ view : (Msg -> msg) -> Style style msg -> Model -> Element msg view msgMapper style (IsExpanded isExpanded) = { onToggle = ToggleCollapsable >> msgMapper , isExpanded = isExpanded - , icon = Element.none + , icon = always Element.none , text = "Title" , content = Element.text <| "Hello World" } diff --git a/example/src/Example/Icon.elm b/example/src/Example/Icon.elm new file mode 100644 index 0000000..1cd41c5 --- /dev/null +++ b/example/src/Example/Icon.elm @@ -0,0 +1,127 @@ +module Example.Icon exposing (Model, Msg, init, subscriptions, update, view) + +import Browser +import Element exposing (Element) +import FeatherIcons +import Widget +import Widget.Style exposing (ButtonStyle, RowStyle) +import Widget.Style.Material as Material +import Material.Icons exposing (offline_bolt) +import Material.Icons.Types exposing (Coloring(..)) +import Widget.Icon exposing (Icon) +import Material.Icons.Action +import Widget.Icon exposing (Icon) +import FeatherIcons +import Widget.Icon exposing (Icon) +import FontAwesome.Icon +import FontAwesome.Solid +import FontAwesome.Svg +import Widget.Icon exposing (Icon) +import Ionicon +import Widget.Icon exposing (Icon) +import Octicons +import Widget.Icon exposing (Icon) +import Heroicons.Solid +import Widget.Icon exposing (Icon) +import Ant.Icons.Svg +import Widget.Icon exposing (Icon) +import Zondicons +import Widget.Icon exposing (Icon) + +type alias Style style msg = + { style + | primaryButton : ButtonStyle msg + , button : ButtonStyle msg + , row : RowStyle msg + } + + +materialStyle : Style {} msg +materialStyle = + { primaryButton = Material.containedButton Material.defaultPalette + , button = Material.outlinedButton Material.defaultPalette + , row = Material.row + } + + +type Model + = () + + +type Msg + = () + + +init : ( Model, Cmd Msg ) +init = + ( IsButtonEnabled True + , Cmd.none + ) + + +update : Msg -> Model -> ( Model, Cmd Msg ) +update msg _ = + case msg of + () -> + ( () + , Cmd.none + ) + + +subscriptions : Model -> Sub Msg +subscriptions _ = + Sub.none + + +{-| You can remove the msgMapper. But by doing so, make sure to also change `msg` to `Msg` in the line below. +-} +view : (Msg -> msg) -> Style style msg -> Model -> Element msg +view msgMapper style (IsButtonEnabled isButtonEnabled) = + [ Material.Icons.done + |> Widget.Icon.elmMaterialIcons Color + , Material.Icons.Action.done + |> Widget.Icon.materialIcons + , FeatherIcons.check + |> Widget.Icon.elmFeather FeatherIcons.toHtml + , FontAwesome.Solid.check + |> Widget.Icon.elmFontawesome FontAwesome.Svg.viewIcon + , Ionicon.done + |> Widget.Icon.elmIonicons + , Octicons.check + |> Widget.Icon.elmOcticons + { withSize = Octicons.size + , withColor = Octicons.color + , defaultOptions = Octicons.defaultOptions + } + ,Heroicons.Solid.check + |> Widget.Icon.elmHeroicons + , Ant.Icons.Svg.checkOutlined + |> Widget.Icon.antDesignIconsElm + , Zondicons.checkmark + |> Widget.Icon.elmZondicons + ] + |> List.map (\icon -> + Widget.button style.primaryButton + { text = "Done" + , icon = icon + , onPress = + if isButtonEnabled then + ChangedButtonStatus False + |> msgMapper + |> Just + + else + Nothing + } + ) + |> Element.wrappedRow [] + + +main : Program () Model Msg +main = + Browser.element + { init = always init + , view = \model -> model |> view identity materialStyle |> Element.layout [] + , update = update + , subscriptions = subscriptions + } diff --git a/example/src/Example/Modal.elm b/example/src/Example/Modal.elm index 4220781..4da3565 100644 --- a/example/src/Example/Modal.elm +++ b/example/src/Example/Modal.elm @@ -6,7 +6,7 @@ import FeatherIcons import Widget import Widget.Style exposing (ButtonStyle, ColumnStyle) import Widget.Style.Material as Material - +import Widget.Icon as Icon type alias Style style msg = { style @@ -59,10 +59,7 @@ view msgMapper style (IsEnabled isEnabled) = { text = "show Modal" , icon = FeatherIcons.eye - |> FeatherIcons.withSize 16 - |> FeatherIcons.toHtml [] - |> Element.html - |> Element.el [] + |> Icon.elmFeather FeatherIcons.toHtml , onPress = ToggleModal True |> msgMapper diff --git a/example/src/Example/MultiSelect.elm b/example/src/Example/MultiSelect.elm index 025b336..1ad72a9 100644 --- a/example/src/Example/MultiSelect.elm +++ b/example/src/Example/MultiSelect.elm @@ -68,7 +68,7 @@ view msgMapper style (Selected selected) = |> List.map (\int -> { text = String.fromInt int - , icon = Element.none + , icon = always Element.none } ) , onSelect = ChangedSelected >> msgMapper >> Just diff --git a/example/src/Example/Select.elm b/example/src/Example/Select.elm index 595c869..fa72d7f 100644 --- a/example/src/Example/Select.elm +++ b/example/src/Example/Select.elm @@ -60,7 +60,7 @@ view msgMapper style (Selected selected) = |> List.map (\int -> { text = String.fromInt int - , icon = Element.none + , icon = always Element.none } ) , onSelect = ChangedSelected >> msgMapper >> Just diff --git a/example/src/Example/SortTable.elm b/example/src/Example/SortTable.elm index 8384959..20656e6 100644 --- a/example/src/Example/SortTable.elm +++ b/example/src/Example/SortTable.elm @@ -31,7 +31,7 @@ materialStyle = |> .panel |> .content |> .expandIcon - , defaultIcon = Element.none + , defaultIcon = always Element.none } } } diff --git a/example/src/Example/Tab.elm b/example/src/Example/Tab.elm index e664703..15d905c 100644 --- a/example/src/Example/Tab.elm +++ b/example/src/Example/Tab.elm @@ -60,7 +60,7 @@ view msgMapper style (Selected selected) = |> List.map (\int -> { text = "Tab " ++ (int |> String.fromInt) - , icon = Element.none + , icon = always Element.none } ) , onSelect = ChangedTab >> msgMapper >> Just diff --git a/example/src/Example/TextInput.elm b/example/src/Example/TextInput.elm index 7307614..99e675f 100644 --- a/example/src/Example/TextInput.elm +++ b/example/src/Example/TextInput.elm @@ -75,7 +75,7 @@ view msgMapper style model = |> Set.toList |> List.map (\string -> - { icon = Element.none + { icon = always Element.none , text = string , onPress = string @@ -105,7 +105,7 @@ view msgMapper style model = |> msgMapper |> Just , text = string - , icon = Element.none + , icon = always Element.none } ) |> Element.wrappedRow [ Element.spacing 10 ] diff --git a/example/src/Main.elm b/example/src/Main.elm index cbd62ab..ce074ec 100644 --- a/example/src/Main.elm +++ b/example/src/Main.elm @@ -25,7 +25,8 @@ import Time import Widget import Widget.Layout as Layout exposing (Layout, Part) import Widget.ScrollingNav as ScrollingNav - +import FeatherIcons +import Widget.Icon as Icon type alias LoadedModel = { stateless : Stateless.Model @@ -321,11 +322,11 @@ view model = , actions = [ { onPress = Just <| Load "https://package.elm-lang.org/packages/Orasund/elm-ui-widgets/latest/" , text = "Docs" - , icon = Icons.book |> Element.html |> Element.el [] + , icon = FeatherIcons.book |> Icon.elmFeather FeatherIcons.toHtml } , { onPress = Just <| Load "https://github.com/Orasund/elm-ui-widgets" , text = "Github" - , icon = Icons.github |> Element.html |> Element.el [] + , icon = FeatherIcons.github |> Icon.elmFeather FeatherIcons.toHtml } , { onPress = if m.theme /= Material then @@ -334,7 +335,7 @@ view model = else Nothing , text = "Material Theme" - , icon = Icons.penTool |> Element.html |> Element.el [] + , icon = FeatherIcons.penTool |> Icon.elmFeather FeatherIcons.toHtml } , { onPress = if m.theme /= DarkMaterial then @@ -343,7 +344,7 @@ view model = else Nothing , text = "Dark Material Theme" - , icon = Icons.penTool |> Element.html |> Element.el [] + , icon = FeatherIcons.penTool |> Icon.elmFeather FeatherIcons.toHtml } ] , onChangedSidebar = ChangedSidebar @@ -438,7 +439,7 @@ viewLoaded m = |> Maybe.map ToggledExample |> Maybe.withDefault Idle ) - , icon = Element.none + , icon = always Element.none , text = "States" , content = diff --git a/example/src/Reusable.elm b/example/src/Reusable.elm index f16abee..69c5d0d 100644 --- a/example/src/Reusable.elm +++ b/example/src/Reusable.elm @@ -18,7 +18,7 @@ snackbar style addSnackbar = , False ) , text = "Add Notification" - , icon = Element.none + , icon = always Element.none } , Widget.button style.button { onPress = @@ -28,7 +28,7 @@ snackbar style addSnackbar = , True ) , text = "Add Notification with Action" - , icon = Element.none + , icon = always Element.none } ] |> Element.column Grid.simple diff --git a/example/src/View/Test.elm b/example/src/View/Test.elm index e129f00..3740229 100644 --- a/example/src/View/Test.elm +++ b/example/src/View/Test.elm @@ -6,6 +6,8 @@ import Icons import Set import Widget import Widget.Layout exposing (Part(..)) +import FeatherIcons +import Widget.Icon as Icon button : msg -> Style msg -> List ( String, Element msg ) @@ -13,7 +15,7 @@ button idle style = [ ( "Button" , Widget.button style.button { text = "Button" - , icon = Icons.triangle |> Element.html |> Element.el [] + , icon = FeatherIcons.triangle |> Icon.elmFeather FeatherIcons.toHtml , onPress = Just idle } ) @@ -26,14 +28,14 @@ button idle style = , ( "Icon button" , Widget.iconButton style.button { text = "Button" - , icon = Icons.triangle |> Element.html |> Element.el [] + , icon = FeatherIcons.triangle |> Icon.elmFeather FeatherIcons.toHtml , onPress = Just idle } ) , ( "Disabled button" , Widget.button style.button { text = "Button" - , icon = Icons.triangle |> Element.html |> Element.el [] + , icon = FeatherIcons.triangle |> Icon.elmFeather FeatherIcons.toHtml , onPress = Nothing } ) @@ -41,7 +43,7 @@ button idle style = , Widget.selectButton style.button ( False , { text = "Button" - , icon = Icons.triangle |> Element.html |> Element.el [] + , icon = FeatherIcons.triangle |> Icon.elmFeather FeatherIcons.toHtml , onPress = Just idle } ) @@ -50,7 +52,7 @@ button idle style = , Widget.selectButton style.button ( True , { text = "Button" - , icon = Icons.triangle |> Element.html |> Element.el [] + , icon = FeatherIcons.triangle |> Icon.elmFeather FeatherIcons.toHtml , onPress = Just idle } ) @@ -93,7 +95,7 @@ select idle style = |> List.map (\int -> { text = String.fromInt int - , icon = Element.none + , icon = always Element.none } ) , onSelect = always idle >> Just @@ -111,7 +113,7 @@ select idle style = |> List.map (\int -> { text = String.fromInt int - , icon = Element.none + , icon = always Element.none } ) , onSelect = always idle >> Just @@ -129,7 +131,7 @@ select idle style = |> List.map (\int -> { text = String.fromInt int - , icon = Element.none + , icon = always Element.none } ) , onSelect = always idle >> Just @@ -147,7 +149,7 @@ select idle style = |> List.map (\int -> { text = String.fromInt int - , icon = Element.none + , icon = always Element.none } ) , onSelect = always Nothing @@ -165,7 +167,7 @@ select idle style = |> List.map (\int -> { text = String.fromInt int - , icon = Element.none + , icon = always Element.none } ) , onSelect = always idle >> Just @@ -188,7 +190,7 @@ multiSelect idle style = |> List.map (\int -> { text = String.fromInt int - , icon = Element.none + , icon = always Element.none } ) , onSelect = always idle >> Just @@ -206,7 +208,7 @@ multiSelect idle style = |> List.map (\int -> { text = String.fromInt int - , icon = Element.none + , icon = always Element.none } ) , onSelect = always idle >> Just @@ -224,7 +226,7 @@ multiSelect idle style = |> List.map (\int -> { text = String.fromInt int - , icon = Element.none + , icon = always Element.none } ) , onSelect = always idle >> Just @@ -242,7 +244,7 @@ multiSelect idle style = |> List.map (\int -> { text = String.fromInt int - , icon = Element.none + , icon =always Element.none } ) , onSelect = always Nothing @@ -260,7 +262,7 @@ multiSelect idle style = |> List.map (\int -> { text = String.fromInt int - , icon = Element.none + , icon = always Element.none } ) , onSelect = always idle >> Just @@ -279,7 +281,7 @@ expansionPanel idle style = [ ( "Collapsed" , { onToggle = always idle , isExpanded = False - , icon = Icons.triangle |> Element.html |> Element.el [] + , icon = FeatherIcons.triangle |> Icon.elmFeather FeatherIcons.toHtml , text = "Button" , content = Element.text <| "Hidden Message" } @@ -288,7 +290,7 @@ expansionPanel idle style = , ( "Expanded" , { onToggle = always idle , isExpanded = True - , icon = Icons.triangle |> Element.html |> Element.el [] + , icon = FeatherIcons.triangle |> Icon.elmFeather FeatherIcons.toHtml , text = "Button" , content = Element.text <| "Hidden Message" } @@ -308,7 +310,7 @@ tab idle style = |> List.map (\int -> { text = int |> String.fromInt - , icon = Element.none + , icon = always Element.none } ) , onSelect = always idle >> Just @@ -334,7 +336,7 @@ tab idle style = |> List.map (\int -> { text = int |> String.fromInt - , icon = Element.none + , icon = always Element.none } ) , onSelect = always idle >> Just @@ -492,11 +494,11 @@ textInput idle style = ) , ( "Some chips" , { chips = - [ { icon = Icons.triangle |> Element.html |> Element.el [] + [ { icon = FeatherIcons.triangle |> Icon.elmFeather FeatherIcons.toHtml , text = "A" , onPress = Just idle } - , { icon = Icons.circle |> Element.html |> Element.el [] + , { icon = FeatherIcons.circle |> Icon.elmFeather FeatherIcons.toHtml , text = "B" , onPress = Just idle } diff --git a/src/Internal/Button.elm b/src/Internal/Button.elm index bf1501c..352e005 100644 --- a/src/Internal/Button.elm +++ b/src/Internal/Button.elm @@ -10,12 +10,12 @@ import Element exposing (Element) import Element.Input as Input import Element.Region as Region import Widget.Style exposing (ButtonStyle) - +import Widget.Icon exposing (Icon) type alias Button msg = { text : String , onPress : Maybe msg - , icon : Element Never + , icon : Icon } @@ -38,7 +38,13 @@ iconButton style { onPress, text, icon } = ++ [ Region.description text ] ) { onPress = onPress - , label = icon |> Element.map never |> Element.el style.content.elementRow + , label = icon + (if onPress == Nothing then + style.content.content.icon.ifDisabled + + else + style.content.content.icon.otherwise + ) |> Element.map never |> Element.el style.content.elementRow } @@ -47,7 +53,7 @@ textButton style { onPress, text } = button style { onPress = onPress , text = text - , icon = Element.none + , icon = always Element.none } @@ -68,7 +74,13 @@ button style { onPress, text, icon } = { onPress = onPress , label = Element.row style.content.elementRow - [ icon |> Element.map never - , Element.text text |> Element.el style.content.contentText + [ icon + (if onPress == Nothing then + style.content.content.icon.ifDisabled + + else + style.content.content.icon.otherwise + ) |> Element.map never + , Element.text text |> Element.el style.content.content.text.contentText ] } diff --git a/src/Internal/ExpansionPanel.elm b/src/Internal/ExpansionPanel.elm index 3a967cb..256d241 100644 --- a/src/Internal/ExpansionPanel.elm +++ b/src/Internal/ExpansionPanel.elm @@ -6,11 +6,11 @@ module Internal.ExpansionPanel exposing (ExpansionPanel, expansionPanel) import Element exposing (Element) import Element.Events as Events import Widget.Style exposing (ExpansionPanelStyle) - +import Widget.Icon exposing (Icon) type alias ExpansionPanel msg = { onToggle : Bool -> msg - , icon : Element Never + , icon : Icon , text : String , content : Element msg , isExpanded : Bool @@ -28,15 +28,22 @@ expansionPanel style model = :: style.content.panel.elementRow ) [ Element.row style.content.panel.content.label.elementRow - [ model.icon |> Element.map never - , model.text |> Element.text + [ model.icon + style.content.panel.content.label.content.icon + |> Element.map never + , model.text + |> Element.text + |> Element.el style.content.panel.content.label.content.text.elementText ] , Element.map never <| if model.isExpanded then style.content.panel.content.collapseIcon + style.content.panel.content.label.content.icon + else style.content.panel.content.expandIcon + style.content.panel.content.label.content.icon ] , if model.isExpanded then Element.el style.content.content.element <| model.content diff --git a/src/Internal/Select.elm b/src/Internal/Select.elm index a372209..64eb662 100644 --- a/src/Internal/Select.elm +++ b/src/Internal/Select.elm @@ -5,14 +5,14 @@ import Element.Input as Input import Internal.Button exposing (Button) import Set exposing (Set) import Widget.Style exposing (ButtonStyle) - +import Widget.Icon exposing (Icon) type alias Select msg = { selected : Maybe Int , options : List { text : String - , icon : Element Never + , icon : Icon } , onSelect : Int -> Maybe msg } @@ -23,7 +23,7 @@ type alias MultiSelect msg = , options : List { text : String - , icon : Element Never + , icon : Icon } , onSelect : Int -> Maybe msg } @@ -49,8 +49,19 @@ selectButton style ( selected, b ) = { onPress = b.onPress , label = Element.row style.content.elementRow - [ b.icon |> Element.map never - , Element.text b.text |> Element.el style.content.contentText + [ b.icon + (if b.onPress == Nothing then + style.content.content.icon.ifDisabled + + else if selected then + style.content.content.icon.ifActive + + else + style.content.content.icon.otherwise + ) + + |> Element.map never + , Element.text b.text |> Element.el style.content.content.text.contentText ] } diff --git a/src/Widget.elm b/src/Widget.elm index fb7669e..1920d7c 100644 --- a/src/Widget.elm +++ b/src/Widget.elm @@ -144,8 +144,17 @@ import Internal.Tab as Tab import Internal.TextInput as TextInput import Set exposing (Set) import Widget.Style exposing (ButtonStyle, ColumnStyle, DialogStyle, ExpansionPanelStyle, ProgressIndicatorStyle, RowStyle, SortTableStyle, SwitchStyle, TabStyle, TextInputStyle) +import Color exposing (Color) +{---------------------------------------------------------- +- ICON +----------------------------------------------------------} +type alias Icon = + { size : Int + , color : Color + } + -> Element Never {---------------------------------------------------------- - BUTTON @@ -156,7 +165,7 @@ import Widget.Style exposing (ButtonStyle, ColumnStyle, DialogStyle, ExpansionPa -} type alias Button msg = { text : String - , icon : Element Never + , icon : Icon , onPress : Maybe msg } @@ -175,7 +184,7 @@ iconButton : ButtonStyle msg -> { text : String - , icon : Element Never + , icon : Icon , onPress : Maybe msg } -> Element msg @@ -216,7 +225,7 @@ button : ButtonStyle msg -> { text : String - , icon : Element Never + , icon : Icon , onPress : Maybe msg } -> Element msg @@ -281,7 +290,7 @@ type alias Select msg = , options : List { text : String - , icon : Element Never + , icon : Icon } , onSelect : Int -> Maybe msg } @@ -299,7 +308,7 @@ type alias MultiSelect msg = , options : List { text : String - , icon : Element Never + , icon : Icon } , onSelect : Int -> Maybe msg } @@ -391,7 +400,7 @@ dialog = -} type alias ExpansionPanel msg = { onToggle : Bool -> msg - , icon : Element Never + , icon : Icon , text : String , content : Element msg , isExpanded : Bool @@ -404,7 +413,7 @@ expansionPanel : ExpansionPanelStyle msg -> { onToggle : Bool -> msg - , icon : Element Never + , icon : Icon , text : String , content : Element msg , isExpanded : Bool diff --git a/src/Widget/Icon.elm b/src/Widget/Icon.elm index e69de29..c2ea922 100644 --- a/src/Widget/Icon.elm +++ b/src/Widget/Icon.elm @@ -0,0 +1,249 @@ +module Widget.Icon exposing (Icon, antDesignIconsElm, elmFeather, elmFontawesome, elmHeroicons, elmIonicons, elmMaterialIcons, elmOcticons, elmZondicons, materialIcons) + +import Color exposing (Color) +import Dict exposing (size) +import Element exposing (Element) +import Html exposing (Html) +import Svg exposing (Svg) +import Svg.Attributes + + +type alias Icon = + { size : Int + , color : Color + } + -> Element Never + + +{-| For using [icidasset/elm-material-icons](https://dark.elm.dmy.fr/packages/icidasset/elm-material-icons/latest/) + +``` +import Material.Icons exposing (offline_bolt) +import Material.Icons.Types exposing (Coloring(..)) +import Widget.Icon exposing (Icon) + +check : Widget.Icon +check = + Material.Icons.done + |> Widget.Icon.elmMaterialIcons Color +``` + +-} +elmMaterialIcons : (Color -> coloring) -> (Int -> coloring -> Html Never) -> Icon +elmMaterialIcons wrapper fun = + \{ size, color } -> + fun size (wrapper color) + |> Element.html + + +{-| For using [danmarcab/material-icons](https://dark.elm.dmy.fr/packages/danmarcab/material-icons/latest/) + +``` +import Material.Icons.Action +import Widget.Icon exposing (Icon) + +check : Widget.Icon +check = + Material.Icons.Action.done + |> Widget.Icon.materialIcons +``` + +-} +materialIcons : (Int -> Color -> Svg Never) -> Icon +materialIcons fun = + \{ size, color } -> + fun size color + |> List.singleton + |> Svg.svg [] + |> Element.html + + +{-| For using [feathericons/elm-feather](https://dark.elm.dmy.fr/packages/feathericons/elm-feather/latest/) + +``` +import FeatherIcons +import Widget.Icon exposing (Icon) + +check : Widget.Icon +check = + FeatherIcons.check + |> Widget.Icon.elmFeather FeatherIcons.toHtml +``` + +-} +elmFeather : (List (Svg.Attribute Never) -> icon -> Html Never) -> icon -> Icon +elmFeather fun icon = + \{ size, color } -> + icon + |> fun + [ Svg.Attributes.width <| String.fromInt size + , Svg.Attributes.height <| String.fromInt size + , Svg.Attributes.stroke <| Color.toCssString color + ] + |> Element.html + |> Element.el [] + + +{-| For using [lattyware/elm-fontawesome](https://dark.elm.dmy.fr/packages/lattyware/elm-fontawesome/latest) + +``` +import FontAwesome.Icon +import FontAwesome.Solid +import FontAwesome.Svg +import Widget.Icon exposing (Icon) + +check : Widget.Icon +check = + FontAwesome.Solid.check + |> Widget.Icon.elmFontawesome FontAwesome.Svg.viewIcon +``` + +-} +elmFontawesome : (icon -> Svg Never) -> icon -> Icon +elmFontawesome fun icon = + \{ size, color } -> + icon + |> fun + |> List.singleton + |> Svg.svg + [ Svg.Attributes.width <| String.fromInt size + , Svg.Attributes.height <| String.fromInt size + , Svg.Attributes.stroke <| Color.toCssString color + ] + |> Element.html + + +{-| For using [j-panasiuk/elm-ionicons](https://dark.elm.dmy.fr/packages/j-panasiuk/elm-ionicons/latest/) + +``` +import Ionicon +import Widget.Icon exposing (Icon) + +check : Widget.Icon +check = + Ionicon.done + |> Widget.Icon.elmIonicons +``` + +-} +elmIonicons : + (Int + -> + { red : Float + , green : Float + , blue : Float + , alpha : Float + } + -> Html Never + ) + -> Icon +elmIonicons fun = + \{ size, color } -> + fun size (Color.toRgba color) + |> Element.html + + +{-| For using [capitalist/elm-octicons](https://dark.elm.dmy.fr/packages/capitalist/elm-octicons/latest) + +``` +import Octicons +import Widget.Icon exposing (Icon) + +check : Widget.Icon +check = + Octicons.check + |> Widget.Icon.elmOcticons + { withSize = Octicons.size + , withColor = Octicons.color + , defaultOptions = Octicons.defaultOptions + } +``` + +-} +elmOcticons : + { withSize : Int -> options -> options + , withColor : String -> options -> options + , defaultOptions : options + } + -> (options -> Html Never) + -> Icon +elmOcticons { withSize, withColor, defaultOptions } fun = + \{ size, color } -> + (defaultOptions + |> withSize size + |> withColor (Color.toCssString color) + ) + |> fun + |> Element.html + + +{-| For using [jasonliang-dev/elm-heroicons](https://dark.elm.dmy.fr/packages/jasonliang-dev/elm-heroicons/latest) + +``` +import Heroicons.Solid +import Widget.Icon exposing (Icon) + +check : Widget.Icon +check = + Heroicons.Solid.check + |> Widget.Icon.elmHeroicons +``` + +-} +elmHeroicons : (List (Svg.Attribute Never) -> Html Never) -> Icon +elmHeroicons fun = + \{ size, color } -> + fun + [ Svg.Attributes.width <| String.fromInt size + , Svg.Attributes.height <| String.fromInt size + , Svg.Attributes.stroke <| Color.toCssString color + ] + |> Element.html + + +{-| For using [lemol/ant-design-icons-elm](https://dark.elm.dmy.fr/packages/lemol/ant-design-icons-elm/latest) + +``` +import Ant.Icons.Svg +import Widget.Icon exposing (Icon) + +check : Widget.Icon +check = + Ant.Icons.Svg.checkOutlined + |> Widget.Icon.antDesignIconsElm +``` + +-} +antDesignIconsElm : (List (Svg.Attribute Never) -> Html Never) -> Icon +antDesignIconsElm fun = + \{ size, color } -> + fun + [ Svg.Attributes.width <| String.fromInt size + , Svg.Attributes.height <| String.fromInt size + , Svg.Attributes.stroke <| Color.toCssString color + ] + |> Element.html + + +{-| For using [pehota/elm-zondicons](https://dark.elm.dmy.fr/packages/pehota/elm-zondicons/latest) + +``` +import Zondicons +import Widget.Icon exposing (Icon) + +check : Widget.Icon +check = + Zondicons.checkmark + |> Widget.Icon.elmZondicons +``` + +-} +elmZondicons : (List (Svg.Attribute Never) -> Html Never) -> Icon +elmZondicons fun = + \{ size, color } -> + fun + [ Svg.Attributes.width <| String.fromInt size + , Svg.Attributes.height <| String.fromInt size + , Svg.Attributes.stroke <| Color.toCssString color + ] + |> Element.html diff --git a/src/Widget/Layout.elm b/src/Widget/Layout.elm index 19b589c..b4cba70 100644 --- a/src/Widget/Layout.elm +++ b/src/Widget/Layout.elm @@ -157,7 +157,7 @@ view style { search, title, onChangedSidebar, menu, actions, window, dialog, lay then [ Widget.iconButton style.menuButton { onPress = Just <| onChangedSidebar <| Just LeftSheet - , icon = style.menuIcon |> Element.map never + , icon = style.menuIcon , text = "Menu" } , menu.selected @@ -334,7 +334,7 @@ view style { search, title, onChangedSidebar, menu, actions, window, dialog, lay content |> style.layout (List.concat - [ style.element + [ style.container , [ Element.inFront nav , Element.inFront snackbar ] diff --git a/src/Widget/ScrollingNav.elm b/src/Widget/ScrollingNav.elm index 3c826b3..b5cc9b4 100644 --- a/src/Widget/ScrollingNav.elm +++ b/src/Widget/ScrollingNav.elm @@ -181,7 +181,7 @@ toSelect onSelect ({ arrangement, toString, fromString } as model) = |> List.map (\s -> { text = toString s - , icon = Element.none + , icon = always Element.none } ) , onSelect = onSelect diff --git a/src/Widget/Style.elm b/src/Widget/Style.elm index 610aa2f..820e57d 100644 --- a/src/Widget/Style.elm +++ b/src/Widget/Style.elm @@ -8,7 +8,13 @@ module Widget.Style exposing (ButtonStyle, SwitchStyle, ColumnStyle, DialogStyle import Element exposing (Attribute, Element) import Html exposing (Html) +import Widget.Icon as Icon exposing (Icon) +import Color exposing (Color) +type alias IconStyle = + { size : Int + , color : Color + } {-| -} type alias SwitchStyle msg = @@ -42,7 +48,14 @@ type alias ButtonStyle msg = , otherwise : List (Attribute msg) , content : { elementRow : List (Attribute msg) - , contentText : List (Attribute msg) + , content : + { text : {contentText : List (Attribute msg)} + , icon : + { ifDisabled : IconStyle + , ifActive : IconStyle + , otherwise : IconStyle + } + } } } @@ -82,9 +95,14 @@ type alias ExpansionPanelStyle msg = , content : { label : { elementRow : List (Attribute msg) + , content : + { icon : IconStyle + , text : { elementText : List (Attribute msg)} + } } - , expandIcon : Element Never - , collapseIcon : Element Never + , expandIcon : Icon + , collapseIcon : Icon + , icon : IconStyle } } , content : @@ -164,9 +182,9 @@ type alias SortTableStyle msg = { elementTable : List (Attribute msg) , content : { header : ButtonStyle msg - , ascIcon : Element Never - , descIcon : Element Never - , defaultIcon : Element Never + , ascIcon : Icon + , descIcon : Icon + , defaultIcon : Icon } } @@ -178,7 +196,7 @@ type alias SortTableStyle msg = -} type alias LayoutStyle msg = - { element : List (Attribute msg) + { container : List (Attribute msg) , snackbar : SnackbarStyle msg , layout : List (Attribute msg) -> Element msg -> Html msg , header : List (Attribute msg) @@ -186,11 +204,11 @@ type alias LayoutStyle msg = , sheetButton : ButtonStyle msg , menuButton : ButtonStyle msg , menuTabButton : ButtonStyle msg - , menuIcon : Element Never - , moreVerticalIcon : Element Never + , menuIcon : Icon + , moreVerticalIcon : Icon , spacing : Int , title : List (Attribute msg) - , searchIcon : Element Never + , searchIcon : Icon , search : List (Attribute msg) , searchFill : List (Attribute msg) } diff --git a/src/Widget/Style/Material.elm b/src/Widget/Style/Material.elm index c816f3b..dfc120c 100644 --- a/src/Widget/Style/Material.elm +++ b/src/Widget/Style/Material.elm @@ -187,7 +187,7 @@ import Widget.Style import Widget.Style.Customize as Customize import Widget.Style.Material.Color as MaterialColor import Widget.Style.Material.Typography as Typography - +import Widget.Icon as Icon exposing (Icon) fromColor : Color -> Element.Color fromColor = @@ -308,7 +308,18 @@ baseButton _ = , Element.width <| Element.minimum 32 <| Element.shrink , Element.centerY ] - , contentText = [ Element.centerX ] + , content = { text = {contentText = [ Element.centerX ]} + , icon = {ifDisabled = { size = 18 + , color = MaterialColor.gray + } + , ifActive = { size = 18 + , color = MaterialColor.gray + } + , otherwise = { size = 18 + , color = MaterialColor.gray + } + } + } } } @@ -377,7 +388,24 @@ containedButton palette = { elementRow = (baseButton palette |> .content |> .elementRow) ++ [ Element.paddingXY 8 0 ] - , contentText = baseButton palette |> .content |> .contentText + , content = {text = {contentText = baseButton palette |> (\b -> b.content.content.text.contentText) } + , icon = + { ifActive = + { size = 18 + , color = palette.primary + |> MaterialColor.accessibleTextColor + } + , ifDisabled = + { size = 18 + , color = MaterialColor.gray + } + , otherwise = + { size = 18 + , color = palette.primary + |> MaterialColor.accessibleTextColor + } + } + } } } @@ -438,10 +466,30 @@ outlinedButton palette = |> .elementRow ) ++ [ Element.paddingXY 8 0 ] - , contentText = - baseButton palette - |> .content - |> .contentText + , content = + { text = + {contentText = + baseButton palette + |> .content + |> .content + |> .text + |> .contentText + } + , icon = + { ifActive = + { size = 18 + , color = palette.primary + } + , ifDisabled = + { size = 18 + , color = MaterialColor.gray + } + , otherwise = + { size = 18 + , color = palette.primary + } + } + } } } @@ -490,8 +538,24 @@ textButton palette = , otherwise = [] , content = - { elementRow = baseButton palette |> .content |> .elementRow - , contentText = baseButton palette |> .content |> .contentText + { elementRow = baseButton palette |> (\b -> b.content.elementRow) + , content = + { text = {contentText = baseButton palette |> (\b -> b.content.content.text.contentText ) } + , icon = + { ifActive = + { size = 18 + , color = palette.primary + } + , ifDisabled = + { size = 18 + , color = MaterialColor.gray + } + , otherwise = + { size = 18 + , color = palette.primary + } + } + } } } @@ -596,7 +660,26 @@ toggleButton palette = |> textAndBackground ) ] - , contentText = [ Element.centerX ] + , content = + { text = {contentText = [ Element.centerX ]} + , icon = + { ifActive = + { size = 24 + , color = palette.surface + |> MaterialColor.accessibleTextColor + } + , ifDisabled = + { size = 24 + , color = MaterialColor.gray + } + , otherwise = + { size = 24 + , color = palette.surface + |> MaterialColor.accessibleTextColor + } + } + + } } } @@ -657,7 +740,21 @@ iconButton palette = , Element.centerY , Element.centerX ] - , contentText = baseButton palette |> .content |> .contentText + , content = { text = {contentText = baseButton palette |> (\b -> b.content.content.text.contentText)} + , icon = { ifActive = + { size = 18 + , color = palette.primary + } + , ifDisabled = + { size = 18 + , color = MaterialColor.gray + } + , otherwise = + { size = 18 + , color = palette.primary + } + } + } } } @@ -884,14 +981,37 @@ chip palette = ] , content = { elementRow = [ Element.spacing 0, Element.centerY ] - , contentText = - [ Element.paddingEach - { top = 0 - , right = 0 - , bottom = 0 - , left = 8 + , content = + { text = { contentText = + [ Element.paddingEach + { top = 0 + , right = 0 + , bottom = 0 + , left = 8 + } + ] } - ] + , icon = + { ifActive = + { size = 18 + , color = palette.on.surface + |> MaterialColor.scaleOpacity 0.12 + |> MaterialColor.accessibleTextColor + } + , ifDisabled = + { size = 18 + , color = palette.on.surface + |> MaterialColor.scaleOpacity 0.12 + |> MaterialColor.accessibleTextColor + } + , otherwise = + { size = 18 + , color = palette.on.surface + |> MaterialColor.scaleOpacity 0.12 + |> MaterialColor.accessibleTextColor + } + } + } } } @@ -1098,14 +1218,18 @@ icon string size = >> Element.el [] -expand_less : Element Never -expand_less = - icon "0 0 48 48" 24 [ Svg.path [ Svg.Attributes.d "M24 16L12 28l2.83 2.83L24 21.66l9.17 9.17L36 28z" ] [] ] +expand_less : Icon +expand_less {size,color}= + icon "0 0 48 48" size [ Svg.path [ Svg.Attributes.d "M24 16L12 28l2.83 2.83L24 21.66l9.17 9.17L36 28z" + , Svg.Attributes.stroke (Color.toCssString color) + ] [] ] -expand_more : Element Never -expand_more = - icon "0 0 48 48" 24 [ Svg.path [ Svg.Attributes.d "M33.17 17.17L24 26.34l-9.17-9.17L12 20l12 12 12-12z" ] [] ] +expand_more : Icon +expand_more {size,color} = + icon "0 0 48 48" size [ Svg.path [ Svg.Attributes.d "M33.17 17.17L24 26.34l-9.17-9.17L12 20l12 12 12-12z" + , Svg.Attributes.stroke (Color.toCssString color) + ] [] ] {-| The expansion Panel is an outdated part of the material design specification. @@ -1135,23 +1259,21 @@ expansionPanel palette = ] , content = { label = - { elementRow = - [ Element.spacing 32 ] + { elementRow = [ Element.spacing 32 ] + , content = + { icon = + { size = 16 + , color = MaterialColor.gray + } + , text = { elementText = []} + } + } + , expandIcon = expand_more + , collapseIcon = expand_less + , icon = + { size = 24 + , color = MaterialColor.gray } - , expandIcon = - expand_more - |> Element.el - [ MaterialColor.gray - |> fromColor - |> Font.color - ] - , collapseIcon = - expand_less - |> Element.el - [ MaterialColor.gray - |> fromColor - |> Font.color - ] } } , content = @@ -1453,7 +1575,23 @@ tabButton palette = , Element.centerY , Element.centerX ] - , contentText = [] + , content = + { text = {contentText = []} + , icon = + { ifActive = + { size = 18 + , color = palette.primary + } + , ifDisabled = + { size = 18 + , color = MaterialColor.gray + } + , otherwise = + { size = 18 + , color = palette.primary + } + } + } } } @@ -1484,19 +1622,24 @@ tab palette = -------------------------------------------------------------------------------} -more_vert : Element Never -more_vert = - icon "0 0 48 48" 24 [ Svg.path [ Svg.Attributes.d "M24 16c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 4c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm0 12c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4z" ] [] ] +more_vert : Icon +more_vert {size,color}= + icon "0 0 48 48" size [ Svg.path [ + Svg.Attributes.d "M24 16c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 4c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm0 12c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4z" + ,Svg.Attributes.stroke <| Color.toCssString color + ] [] ] -search : Element Never -search = - icon "0 0 48 48" 24 [ Svg.path [ Svg.Attributes.d "M31 28h-1.59l-.55-.55C30.82 25.18 32 22.23 32 19c0-7.18-5.82-13-13-13S6 11.82 6 19s5.82 13 13 13c3.23 0 6.18-1.18 8.45-3.13l.55.55V31l10 9.98L40.98 38 31 28zm-12 0c-4.97 0-9-4.03-9-9s4.03-9 9-9 9 4.03 9 9-4.03 9-9 9z" ] [] ] +search : Icon +search {size,color}= + icon "0 0 48 48" size [ Svg.path [ Svg.Attributes.d "M31 28h-1.59l-.55-.55C30.82 25.18 32 22.23 32 19c0-7.18-5.82-13-13-13S6 11.82 6 19s5.82 13 13 13c3.23 0 6.18-1.18 8.45-3.13l.55.55V31l10 9.98L40.98 38 31 28zm-12 0c-4.97 0-9-4.03-9-9s4.03-9 9-9 9 4.03 9 9-4.03 9-9 9z" + ,Svg.Attributes.stroke <| Color.toCssString color ] [] ] -menu : Element Never -menu = - icon "0 0 48 48" 24 [ Svg.path [ Svg.Attributes.d "M6 36h36v-4H6v4zm0-10h36v-4H6v4zm0-14v4h36v-4H6z" ] [] ] +menu : Icon +menu {size,color}= + icon "0 0 48 48" size [ Svg.path [ Svg.Attributes.d "M6 36h36v-4H6v4zm0-10h36v-4H6v4zm0-14v4h36v-4H6z" + ,Svg.Attributes.stroke <| Color.toCssString color ] [] ] menuTabButton : Palette -> ButtonStyle msg @@ -1558,7 +1701,21 @@ menuTabButton palette = , Element.centerY , Element.centerX ] - , contentText = [] + , content = {text = {contentText = []} + , icon = { ifActive = + { size = 18 + , color = palette.primary |> MaterialColor.accessibleTextColor + } + , ifDisabled = + { size = 18 + , color = MaterialColor.gray + } + , otherwise = + { size = 18 + , color = palette.primary |> MaterialColor.accessibleTextColor + } + } + } } } @@ -1618,7 +1775,22 @@ drawerButton palette = [] , content = { elementRow = baseButton palette |> .content |> .elementRow - , contentText = baseButton palette |> .content |> .contentText + , content = + { text = {contentText = baseButton palette |> (\b -> b.content.content.text.contentText)} + , icon = { ifActive = + { size = 18 + , color = palette.primary + } + , ifDisabled = + { size = 18 + , color = MaterialColor.gray + } + , otherwise = + { size = 18 + , color = palette.primary |> MaterialColor.accessibleTextColor + } + } + } } } @@ -1642,7 +1814,7 @@ Technical Remark: -} layout : Palette -> LayoutStyle msg layout palette = - { element = + { container = (palette.background |> textAndBackground) ++ [ Font.family [ Font.typeface "Roboto"