From 9fceb36811bac85a455bd8d7b460a3809b6813e9 Mon Sep 17 00:00:00 2001 From: Lucas Payr Date: Sun, 6 Jun 2021 15:33:01 +0200 Subject: [PATCH 1/5] add MultiSelect Page --- explorer/src/Main.elm | 2 + explorer/src/Page/MultiSelect.elm | 249 ++++++++++++++++++++++++ explorer/src/Page/ProgressIndicator.elm | 64 ++++++ 3 files changed, 315 insertions(+) create mode 100644 explorer/src/Page/MultiSelect.elm create mode 100644 explorer/src/Page/ProgressIndicator.elm diff --git a/explorer/src/Main.elm b/explorer/src/Main.elm index 3496360..21fbf37 100644 --- a/explorer/src/Main.elm +++ b/explorer/src/Main.elm @@ -10,12 +10,14 @@ import Page.SortTable import Page.Switch import Page.Tab import Page.TextInput +import Page.MultiSelect import UIExplorer pages = UIExplorer.firstPage "Button" Page.Button.page |> UIExplorer.nextPage "Select" Page.Select.page + |> UIExplorer.nextPage "Multi Select" Page.MultiSelect.page |> UIExplorer.nextPage "Switch" Page.Switch.page |> UIExplorer.nextPage "Tab" Page.Tab.page |> UIExplorer.nextPage "Password Input" Page.PasswordInput.page diff --git a/explorer/src/Page/MultiSelect.elm b/explorer/src/Page/MultiSelect.elm new file mode 100644 index 0000000..01c20b4 --- /dev/null +++ b/explorer/src/Page/MultiSelect.elm @@ -0,0 +1,249 @@ +module Page.MultiSelect exposing (page) + +{-| This is an example Page. If you want to add your own pages, simple copy and modify this one. +-} +import Browser +import Element exposing (Element) +import Set exposing (Set) +import Widget exposing (ButtonStyle, RowStyle) +import Widget.Material as Material +import Element exposing (Element) +import Element.Background as Background +import Material.Icons as MaterialIcons +import Material.Icons.Types exposing (Coloring(..)) +import Page +import UIExplorer.Story as Story exposing (StorySelectorModel, StorySelectorMsg) +import UIExplorer.Tile as Tile exposing (Context, Tile, TileMsg) +import Widget +import Widget.Customize as Customize +import Widget.Icon as Icon +import Widget.Material as Material +import Widget.Material.Color as MaterialColor +import Widget.Material.Typography as Typography + +{-| The title of this page +-} +title : String +title = + "Multi Select" + + +{-| The description. I've taken this description directly from the [Material-UI-Specification](https://material.io/components/buttons) +-} +description : String +description = + "Select buttons group a set of actions using layout and spacing." + + +{-| List of view functions. Essentially, anything that takes a Button as input. +-} +viewFunctions = + let + viewSelectRow style selected1 selected2 selected3 options onSelect { palette } () = + Widget.multiSelect + { selected = + [ selected1, selected2, selected3] |> List.filterMap identity + |> Set.fromList + , options = options + , onSelect = onSelect + } + |> Widget.buttonRow + { elementRow = Material.row + , content = style palette + } + --Don't forget to change the title + |> Page.viewTile "Widget.buttonRow " + + viewTogggleRow style selected1 selected2 selected3 options onSelect { palette } () = + Widget.multiSelect + { selected = [ selected1, selected2, selected3] |> List.filterMap identity + |> Set.fromList + , options = options + , onSelect = onSelect + } + |> Widget.toggleRow + { elementRow = Material.toggleRow + , content = style palette + } + --Don't forget to change the title + |> Page.viewTile "Widget.toggleRow" + + viewWrappedRow style selected1 selected2 selected3 options onSelect { palette } () = + Widget.multiSelect + { selected = [ selected1, selected2, selected3] |> List.filterMap identity + |> Set.fromList + , options = options + , onSelect = onSelect + } + |> Widget.wrappedButtonRow + { elementRow = Material.row + , content = style palette + } + --Don't forget to change the title + |> Page.viewTile "Widget.wrappedButtonRow" + + viewSelectColumn style selected1 selected2 selected3 options onSelect { palette } () = + Widget.multiSelect + { selected = [ selected1, selected2, selected3] |> List.filterMap identity + |> Set.fromList + , options = options + , onSelect = onSelect + } + |> Widget.buttonColumn + { elementColumn = Material.column + , content = style palette + } + --Don't forget to change the title + |> Page.viewTile "Widget.buttonColumn" + in + [ viewTogggleRow, viewSelectRow, viewSelectColumn, viewWrappedRow ] + |> List.foldl Story.addTile + Story.initStaticTiles + + +{-| Let's you play around with the options. +Note that the order of these stories must follow the order of the arguments from the view functions. +-} +book : Tile.Group ( StorySelectorModel, () ) (TileMsg StorySelectorMsg ()) () +book = + Story.book (Just "Options") + viewFunctions + --Adding a option for different styles. + |> Story.addStory + (Story.optionListStory "Style" + ( "Contained", Material.containedButton ) + [ ( "Outlined", Material.outlinedButton ) + , ( "Text", Material.textButton ) + , ( "Chip", Material.chip ) + , ( "IconButton", Material.iconButton ) + , ( "Toggle", Material.toggleButton ) + ] + ) + --Changing the text of the label + |> Story.addStory + (Story.boolStory "Selected First" + (Just 0,Nothing) + False + ) + |> Story.addStory + (Story.boolStory "Selected Second" + (Just 1,Nothing) + True + ) + |> Story.addStory + (Story.boolStory "Selected Third" + (Just 2,Nothing) + True + ) + --Change the Icon + |> Story.addStory + (Story.optionListStory "Options" + ( "3 Option" + , [ { icon = always Element.none, text = "Submit" } + , { icon = MaterialIcons.done |> Icon.elmMaterialIcons Color, text = "" } + , { icon = MaterialIcons.done |> Icon.elmMaterialIcons Color, text = "Submit" } + ] + ) + [ ( "2 Option" + , [ { icon = always Element.none, text = "Submit" } + , { icon = MaterialIcons.done |> Icon.elmMaterialIcons Color, text = "" } + ] + ) + , ( "1 Option", [ { icon = always Element.none, text = "Submit" } ] ) + ] + ) + --Should an event be triggered when pressing the button? + |> Story.addStory + (Story.boolStory "With event handler" + ( always <| Just (), always Nothing ) + True + ) + |> Story.build + + +{- This next section is essentially just a normal Elm program. -} +-------------------------------------------------------------------------------- +-- Interactive Demonstration +-------------------------------------------------------------------------------- + + +type Model + = Selected (Set Int) + + +type Msg + = ChangedSelected Int + + +init : ( Model, Cmd Msg ) +init = + ( Selected <| Set.empty + , Cmd.none + ) + + +update : Msg -> Model -> ( Model, Cmd Msg ) +update msg (Selected selected) = + case msg of + ChangedSelected int -> + ( selected + |> (if selected |> Set.member int then + Set.remove int + + else + Set.insert int + ) + |> Selected + , 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 : Context -> Model -> Element Msg +view {palette} (Selected selected) = + { selected = selected + , options = + [ 1, 2, 42 ] + |> List.map + (\int -> + { text = String.fromInt int + , icon = always Element.none + } + ) + , onSelect = ChangedSelected >> Just + } + |> Widget.multiSelect + |> Widget.buttonRow + { elementRow = Material.toggleRow + , content = Material.toggleButton palette + } + + +-------------------------------------------------------------------------------- +-- DO NOT MODIFY ANYTHING AFTER THIS LINE +-------------------------------------------------------------------------------- + + +demo : Tile Model Msg () +demo = + { init = always init + , update = update + , view = Page.demo view + , subscriptions = subscriptions + } + + +page = + Page.create + { title = title + , description = description + , book = book + , demo = demo + } + diff --git a/explorer/src/Page/ProgressIndicator.elm b/explorer/src/Page/ProgressIndicator.elm new file mode 100644 index 0000000..f5f472f --- /dev/null +++ b/explorer/src/Page/ProgressIndicator.elm @@ -0,0 +1,64 @@ +module Example.ProgressIndicator exposing (Model, Msg, init, subscriptions, update, view) + +import Browser +import Element exposing (Element) +import Widget exposing (ProgressIndicatorStyle) +import Widget.Material as Material + + +type alias Style style msg = + { style + | progressIndicator : ProgressIndicatorStyle msg + } + + +materialStyle : Style {} msg +materialStyle = + { progressIndicator = Material.progressIndicator Material.defaultPalette + } + + +type Model + = MaybeProgress (Maybe Float) + + +type Msg + = ChangedProgress (Maybe Float) + + +init : ( Model, Cmd Msg ) +init = + ( MaybeProgress Nothing + , Cmd.none + ) + + +update : Msg -> Model -> ( Model, Cmd Msg ) +update msg _ = + case msg of + ChangedProgress maybeFloat -> + ( MaybeProgress maybeFloat + , 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 (MaybeProgress maybeProgress) = + Widget.circularProgressIndicator style.progressIndicator maybeProgress + + +main : Program () Model Msg +main = + Browser.element + { init = always init + , view = \model -> model |> view identity materialStyle |> Element.layout [] + , update = update + , subscriptions = subscriptions + } From ee6046f6b16d244f398ff0e9c89c2d8d2b13c4cf Mon Sep 17 00:00:00 2001 From: Lucas Payr Date: Sun, 6 Jun 2021 21:45:50 +0200 Subject: [PATCH 2/5] Added ProgressIndicator Page --- explorer/src/Main.elm | 2 + explorer/src/Page/ProgressIndicator.elm | 123 ++++++++++++++++++++---- 2 files changed, 106 insertions(+), 19 deletions(-) diff --git a/explorer/src/Main.elm b/explorer/src/Main.elm index 21fbf37..c6a42b0 100644 --- a/explorer/src/Main.elm +++ b/explorer/src/Main.elm @@ -11,6 +11,7 @@ import Page.Switch import Page.Tab import Page.TextInput import Page.MultiSelect +import Page.ProgressIndicator import UIExplorer @@ -25,6 +26,7 @@ pages = |> UIExplorer.nextPage "Sort Table" Page.SortTable.page |> UIExplorer.nextPage "Snackbar" Page.Snackbar.page |> UIExplorer.nextPage "Item" Page.Item.page + |> UIExplorer.nextPage "ProgressIndicator" Page.ProgressIndicator.page main = diff --git a/explorer/src/Page/ProgressIndicator.elm b/explorer/src/Page/ProgressIndicator.elm index f5f472f..d2c4518 100644 --- a/explorer/src/Page/ProgressIndicator.elm +++ b/explorer/src/Page/ProgressIndicator.elm @@ -1,21 +1,89 @@ -module Example.ProgressIndicator exposing (Model, Msg, init, subscriptions, update, view) +module Page.ProgressIndicator exposing (page) +{-| This is an example Page. If you want to add your own pages, simple copy and modify this one. +-} import Browser import Element exposing (Element) import Widget exposing (ProgressIndicatorStyle) import Widget.Material as Material +import Element exposing (Element) +import Element.Background as Background +import Material.Icons as MaterialIcons +import Material.Icons.Types exposing (Coloring(..)) +import Page +import UIExplorer.Story as Story exposing (StorySelectorModel, StorySelectorMsg) +import UIExplorer.Tile as Tile exposing (Context, Tile, TileMsg) +import Widget +import Widget.Customize as Customize +import Widget.Icon as Icon +import Widget.Material as Material +import Widget.Material.Color as MaterialColor +import Widget.Material.Typography as Typography -type alias Style style msg = - { style - | progressIndicator : ProgressIndicatorStyle msg - } +{-| The title of this page +-} +title : String +title = + "Progress Indicator" -materialStyle : Style {} msg -materialStyle = - { progressIndicator = Material.progressIndicator Material.defaultPalette - } +{-| The description. I've taken this description directly from the [Material-UI-Specification](https://material.io/components/buttons) +-} +description : String +description = + "Progress indicators express an unspecified wait time or display the length of a process." + + +{-| List of view functions. Essentially, anything that takes a Button as input. +-} +viewFunctions = + let + viewIndicator style progress indeterminate { palette } () = + Widget.circularProgressIndicator (style palette) + (indeterminate (toFloat progress/ 100 )) + --Don't forget to change the title + |> Page.viewTile "Widget.circularProgressIndicator" + + in + [ viewIndicator ] + |> List.foldl Story.addTile + Story.initStaticTiles + + +{-| Let's you play around with the options. +Note that the order of these stories must follow the order of the arguments from the view functions. +-} +book : Tile.Group ( StorySelectorModel, () ) (TileMsg StorySelectorMsg ()) () +book = + Story.book (Just "Options") + viewFunctions + --Adding a option for different styles. + |> Story.addStory + (Story.optionListStory "Style" + ( "ProgressIndicator", Material.progressIndicator ) + [ ] + ) + --Changing the text of the label + |> Story.addStory + (Story.rangeStory "Progress" + { unit = "%", min = 0, max = 100, default = 50 } + + ) + --Should an event be triggered when pressing the button? + |> Story.addStory + (Story.boolStory "Indeterminate Indicator" + ( always Nothing, Just ) + False + ) + |> Story.build + + + +{- This next section is essentially just a normal Elm program. -} +-------------------------------------------------------------------------------- +-- Interactive Demonstration +-------------------------------------------------------------------------------- type Model @@ -49,16 +117,33 @@ subscriptions _ = {-| 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 (MaybeProgress maybeProgress) = - Widget.circularProgressIndicator style.progressIndicator maybeProgress +view : Context -> Model -> Element Msg +view {palette} (MaybeProgress maybeProgress) = + Widget.circularProgressIndicator (Material.progressIndicator palette) + maybeProgress -main : Program () Model Msg -main = - Browser.element - { init = always init - , view = \model -> model |> view identity materialStyle |> Element.layout [] - , update = update - , subscriptions = subscriptions + +-------------------------------------------------------------------------------- +-- DO NOT MODIFY ANYTHING AFTER THIS LINE +-------------------------------------------------------------------------------- + + +demo : Tile Model Msg () +demo = + { init = always init + , update = update + , view = Page.demo view + , subscriptions = subscriptions + } + + +page = + Page.create + { title = title + , description = description + , book = book + , demo = demo } + + From c0b9e5e22120c293a791052d4f2bf75cf83f4f3c Mon Sep 17 00:00:00 2001 From: Lucas Payr Date: Tue, 8 Jun 2021 08:46:08 +0200 Subject: [PATCH 3/5] Added Modal Page --- explorer/src/Main.elm | 2 + explorer/src/Page/Modal.elm | 280 ++++++++++++++++++++++++++++++++++++ 2 files changed, 282 insertions(+) create mode 100644 explorer/src/Page/Modal.elm diff --git a/explorer/src/Main.elm b/explorer/src/Main.elm index c6a42b0..231dc4f 100644 --- a/explorer/src/Main.elm +++ b/explorer/src/Main.elm @@ -12,6 +12,7 @@ import Page.Tab import Page.TextInput import Page.MultiSelect import Page.ProgressIndicator +import Page.Modal import UIExplorer @@ -27,6 +28,7 @@ pages = |> UIExplorer.nextPage "Snackbar" Page.Snackbar.page |> UIExplorer.nextPage "Item" Page.Item.page |> UIExplorer.nextPage "ProgressIndicator" Page.ProgressIndicator.page + |> UIExplorer.nextPage "Modal" Page.Modal.page main = diff --git a/explorer/src/Page/Modal.elm b/explorer/src/Page/Modal.elm new file mode 100644 index 0000000..328b3fb --- /dev/null +++ b/explorer/src/Page/Modal.elm @@ -0,0 +1,280 @@ +module Page.Modal exposing (page) + +{-| This is an example Page. If you want to add your own pages, simple copy and modify this one. +-} + +import Browser +import Element exposing (Element) +import Element.Background as Background +import Material.Icons as MaterialIcons +import Material.Icons.Types exposing (Coloring(..)) +import Page +import UIExplorer.Story as Story exposing (StorySelectorModel, StorySelectorMsg) +import UIExplorer.Tile as Tile exposing (Context, Tile, TileMsg) +import Widget exposing (ButtonStyle, ColumnStyle) +import Widget.Customize as Customize +import Widget.Icon as Icon +import Widget.Material as Material +import Widget.Material.Color as MaterialColor +import Widget.Material.Typography as Typography + + +{-| The title of this page +-} +title : String +title = + "Modal" + + +{-| The description. I've taken this description directly from the [Material-UI-Specification](https://material.io/components/buttons) +-} +description : String +description = + "All modal surfaces are interruptive by design – their purpose is to have the user focus on content on a surface that appears in front of all other surfaces." + + +{-| List of view functions. Essentially, anything that takes a Button as input. +-} +viewFunctions = + let + viewSingle content onDismiss { palette } () = + let + contentEl = + content + |> Element.text + |> List.singleton + |> Element.paragraph [] + |> List.singleton + |> Widget.column (Material.cardColumn palette) + |> Element.el [ Element.padding 8 ] + in + "Placeholder Text" + |> Element.text + |> Element.el + ([ Element.height <| Element.px 200 + , Element.width <| Element.fill + ] + ++ ([ { onDismiss = onDismiss + , content = contentEl + } + , { onDismiss = onDismiss + , content = + contentEl + |> Element.el + [ Element.moveDown 10 + , Element.moveRight 10 + ] + } + , { onDismiss = onDismiss + , content = + contentEl + |> Element.el + [ Element.moveDown 20 + , Element.moveRight 20 + ] + } + ] + |> Widget.singleModal + ) + ) + --Don't forget to change the title + |> Page.viewTile "Widget.singleModal" + + viewMulti content onDismiss { palette } () = + let + contentEl = + content + |> Element.text + |> List.singleton + |> Element.paragraph [] + |> List.singleton + |> Widget.column (Material.cardColumn palette) + |> Element.el [ Element.padding 8 ] + in + "Placeholder Text" + |> Element.text + |> Element.el + ([ Element.height <| Element.px 200 + , Element.width <| Element.fill + ] + ++ ([ { onDismiss = onDismiss + , content = contentEl + } + , { onDismiss = onDismiss + , content = + contentEl + |> Element.el + [ Element.moveDown 10 + , Element.moveRight 10 + ] + } + , { onDismiss = onDismiss + , content = + contentEl + |> Element.el + [ Element.moveDown 20 + , Element.moveRight 20 + ] + } + ] + |> Widget.multiModal + ) + ) + --Don't forget to change the title + |> Page.viewTile "Widget.multiModal" + in + [ viewSingle, viewMulti ] + |> List.foldl Story.addTile + Story.initStaticTiles + + +{-| Let's you play around with the options. +Note that the order of these stories must follow the order of the arguments from the view functions. +-} +book : Tile.Group ( StorySelectorModel, () ) (TileMsg StorySelectorMsg ()) () +book = + Story.book (Just "Options") + viewFunctions + --Changing the text of the label + |> Story.addStory + (Story.textStory "Content" + "This is a windows that is in front of everything else. You can allow the user to close it by pressing outside of it or disable this feature." + ) + --Should an event be triggered when pressing the button? + |> Story.addStory + (Story.boolStory "With event handler" + ( Just (), Nothing ) + True + ) + |> Story.build + + + +{- This next section is essentially just a normal Elm program. -} +-------------------------------------------------------------------------------- +-- Interactive Demonstration +-------------------------------------------------------------------------------- + + +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 + + +{-| You can remove the msgMapper. But by doing so, make sure to also change `msg` to `Msg` in the line below. +-} +view : Context -> Model -> Element Msg +view { palette } (IsEnabled isEnabled) = + Widget.button (Material.containedButton palette) + { text = "Show Modal" + , icon = MaterialIcons.visibility |> Icon.elmMaterialIcons Color + , onPress = + ToggleModal True + |> Just + } + |> Element.el + ([ Element.height <| Element.minimum 200 <| Element.fill + , Element.width <| Element.minimum 400 <| Element.fill + ] + ++ (if isEnabled then + [ { onDismiss = + ToggleModal False + |> Just + , content = + "Click on the area around this box to close it." + |> Element.text + |> List.singleton + |> Element.paragraph [] + |> List.singleton + |> Widget.column (Material.cardColumn palette) + |> Element.el + [ Element.width <| Element.px 250 + , Element.centerX + , Element.centerY + ] + } + , { onDismiss = Nothing + , content = + "This card can not be selected." + |> Element.text + |> List.singleton + |> Element.paragraph [] + |> List.singleton + |> Widget.column (Material.cardColumn palette) + |> Element.el + [ Element.height <| Element.px 150 + , Element.width <| Element.px 200 + , Element.centerX + , Element.centerY + ] + } + , { onDismiss = Nothing + , content = + "This is message is behind the other two" + |> Element.text + |> List.singleton + |> Element.paragraph [] + |> List.singleton + |> Widget.column (Material.cardColumn palette) + |> Element.el + [ Element.height <| Element.px 300 + , Element.width <| Element.px 300 + , Element.centerX + , Element.centerY + ] + } + ] + |> Widget.multiModal + + else + [] + ) + ) + + + +-------------------------------------------------------------------------------- +-- DO NOT MODIFY ANYTHING AFTER THIS LINE +-------------------------------------------------------------------------------- + + +demo : Tile Model Msg () +demo = + { init = always init + , update = update + , view = Page.demo view + , subscriptions = subscriptions + } + + +page = + Page.create + { title = title + , description = description + , book = book + , demo = demo + } From 576b2e3d649f9ba00fb1f502fec51d7a12110f98 Mon Sep 17 00:00:00 2001 From: Lucas Payr Date: Tue, 8 Jun 2021 13:33:40 +0200 Subject: [PATCH 4/5] Add Layout Page --- explorer/src/Main.elm | 8 +- explorer/src/Page/Layout.elm | 521 +++++++++++++++++++++++++++++++++++ 2 files changed, 526 insertions(+), 3 deletions(-) create mode 100644 explorer/src/Page/Layout.elm diff --git a/explorer/src/Main.elm b/explorer/src/Main.elm index 231dc4f..f8e5152 100644 --- a/explorer/src/Main.elm +++ b/explorer/src/Main.elm @@ -3,16 +3,17 @@ module Main exposing (main) import Element import Page.Button import Page.Item +import Page.Layout +import Page.Modal +import Page.MultiSelect import Page.PasswordInput +import Page.ProgressIndicator import Page.Select import Page.Snackbar import Page.SortTable import Page.Switch import Page.Tab import Page.TextInput -import Page.MultiSelect -import Page.ProgressIndicator -import Page.Modal import UIExplorer @@ -29,6 +30,7 @@ pages = |> UIExplorer.nextPage "Item" Page.Item.page |> UIExplorer.nextPage "ProgressIndicator" Page.ProgressIndicator.page |> UIExplorer.nextPage "Modal" Page.Modal.page + |> UIExplorer.nextPage "Layout" Page.Layout.page main = diff --git a/explorer/src/Page/Layout.elm b/explorer/src/Page/Layout.elm new file mode 100644 index 0000000..8a87c0c --- /dev/null +++ b/explorer/src/Page/Layout.elm @@ -0,0 +1,521 @@ +module Page.Layout exposing (page) + +{-| This is an example Page. If you want to add your own pages, simple copy and modify this one. +-} + +import Browser +import Browser.Events as Events +import Element exposing (Attribute, DeviceClass(..), Element) +import Element.Background as Background +import Element.Border as Border +import Element.Font as Font +import Material.Icons as MaterialIcons +import Material.Icons.Types exposing (Coloring(..)) +import Page +import Time +import UIExplorer.Story as Story exposing (StorySelectorModel, StorySelectorMsg) +import UIExplorer.Tile as Tile exposing (Context, Tile, TileMsg) +import Widget + exposing + ( AppBarStyle + , ButtonStyle + , ColumnStyle + , DialogStyle + , InsetItemStyle + , ItemStyle + , Modal + , TextInput + , TextInputStyle + ) +import Widget.Customize as Customize +import Widget.Icon as Icon exposing (Icon) +import Widget.Layout as Layout +import Widget.Material as Material +import Widget.Material.Color as MaterialColor +import Widget.Material.Typography as Typography +import Widget.Snackbar as Snackbar exposing (Snackbar, SnackbarStyle) + + +{-| The title of this page +-} +title : String +title = + "Button" + + +{-| The description. I've taken this description directly from the [Material-UI-Specification](https://material.io/components/buttons) +-} +description : String +description = + "Buttons allow users to take actions, and make choices, with a single tap." + + +{-| List of view functions. Essentially, anything that takes a Button as input. +-} +viewFunctions = + let + viewMenuBar titleString deviceClass openLeftSheet openRightSheet openTopSheet primaryActions search { palette } () = + Widget.menuBar (Material.menuBar palette) + { title = titleString |> Element.text |> Element.el [] + , deviceClass = deviceClass + , openLeftSheet = openLeftSheet + , openRightSheet = openRightSheet + , openTopSheet = openTopSheet + , primaryActions = + { icon = + MaterialIcons.change_history + |> Icon.elmMaterialIcons Color + , text = "Action" + , onPress = Just () + } + |> List.repeat primaryActions + , search = search + } + |> Element.el [ Element.width <| Element.px 400, Element.scrollbarX ] + --Don't forget to change the title + |> Page.viewTile "Widget.button" + + viewTabBar titleString deviceClass _ openRightSheet openTopSheet primaryActions search { palette } () = + Widget.tabBar (Material.tabBar palette) + { title = titleString |> Element.text |> Element.el [] + , menu = + { selected = Just 0 + , options = + [ "Home", "About" ] + |> List.map + (\string -> + { text = string + , icon = always Element.none + } + ) + , onSelect = always (Just ()) + } + , deviceClass = deviceClass + , openRightSheet = openRightSheet + , openTopSheet = openTopSheet + , primaryActions = + { icon = + MaterialIcons.change_history + |> Icon.elmMaterialIcons Color + , text = "Action" + , onPress = Just () + } + |> List.repeat primaryActions + , search = search + } + |> Element.el [ Element.width <| Element.px 400, Element.scrollbarX ] + --Don't forget to change the title + |> Page.viewTile "Widget.button" + in + [ viewMenuBar, viewTabBar ] + |> List.foldl Story.addTile + Story.initStaticTiles + + +{-| Let's you play around with the options. +Note that the order of these stories must follow the order of the arguments from the view functions. +-} +book : Tile.Group ( StorySelectorModel, () ) (TileMsg StorySelectorMsg ()) () +book = + Story.book (Just "Options") + viewFunctions + --Changing the text of the label + |> Story.addStory + (Story.textStory "Title" + "Title" + ) + --Change the Icon + |> Story.addStory + (Story.optionListStory "Device Class" + ( "Phone", Phone ) + [ ( "Tablet", Tablet ) + , ( "Desktop", Desktop ) + , ( "BigDesktop", BigDesktop ) + ] + ) + --Should an event be triggered when pressing the button? + |> Story.addStory + (Story.boolStory "With openLeftSheet event handler" + ( Just (), Nothing ) + True + ) + |> Story.addStory + (Story.boolStory "With openRightSheet event handler" + ( Just (), Nothing ) + True + ) + |> Story.addStory + (Story.boolStory "With openTopSheet event handler" + ( Just (), Nothing ) + True + ) + --Changing the text of the label + |> Story.addStory + (Story.rangeStory "Primary Actions" + { unit = "Buttons", min = 0, max = 5, default = 3 } + ) + |> Story.addStory + (Story.boolStory "With search" + ( Just + { chips = [] + , text = "Placeholder Text" + , placeholder = Nothing + , label = "Search" + , onChange = always () + } + , Nothing + ) + True + ) + |> Story.build + + + +{- This next section is essentially just a normal Elm program. -} +-------------------------------------------------------------------------------- +-- Interactive Demonstration +-------------------------------------------------------------------------------- + + +container palette = + (palette.background |> MaterialColor.textAndBackground) + ++ [ Font.family + [ Font.typeface "Roboto" + , Font.sansSerif + ] + , Font.size 16 + , Font.letterSpacing 0.5 + ] + + +searchFill palette = + { elementRow = + (palette.surface + |> MaterialColor.textAndBackground + ) + ++ [ Element.height <| Element.px 56 ] + , content = + { chips = + { elementRow = [ Element.spacing 8 ] + , content = Material.chip palette + } + , text = + { elementTextInput = + (palette.surface + |> MaterialColor.textAndBackground + ) + ++ [ Border.width 0 + , Element.mouseOver [] + , Element.focused [] + ] + } + } + } + + +type Part + = LeftSheet + | RightSheet + | Search + + +type alias Model = + { window : + { height : Int + , width : Int + } + , showDialog : Bool + , snackbar : Snackbar String + , active : Maybe Part + , selected : Int + , searchText : String + } + + +type Msg + = ChangedSidebar (Maybe Part) + | Resized { width : Int, height : Int } + | SetSelected Int + | AddSnackbar + | ShowDialog Bool + | SetSearchText String + | TimePassed Int + + +init : ( Model, Cmd Msg ) +init = + ( { window = { height = 200, width = 400 } + , showDialog = False + , snackbar = Snackbar.init + , active = Just RightSheet + , selected = 0 + , searchText = "" + } + , Cmd.none + ) + + +update : Msg -> Model -> ( Model, Cmd Msg ) +update msg model = + case msg of + ChangedSidebar maybePart -> + ( { model | active = maybePart } + , Cmd.none + ) + + Resized window -> + ( { model | window = window } + , Cmd.none + ) + + SetSelected int -> + ( { model | selected = int } + , Cmd.none + ) + + AddSnackbar -> + ( { model | snackbar = model.snackbar |> Snackbar.insert "This is a message" } + , Cmd.none + ) + + ShowDialog bool -> + ( { model | showDialog = bool } + , Cmd.none + ) + + SetSearchText maybeString -> + ( { model | searchText = maybeString } + , Cmd.none + ) + + TimePassed sec -> + ( case model.active of + Just LeftSheet -> + model + + Just RightSheet -> + model + + _ -> + { model + | snackbar = model.snackbar |> Snackbar.timePassed sec + } + , Cmd.none + ) + + +subscriptions : Model -> Sub Msg +subscriptions _ = + Sub.batch + [ Events.onResize (\h w -> Resized { height = h, width = w }) + , Time.every 50 (always (TimePassed 50)) + ] + + +{-| You can remove the msgMapper. But by doing so, make sure to also change `msg` to `Msg` in the line below. +-} +view : Context -> Model -> Element Msg +view { palette } { snackbar, searchText, selected, showDialog, active } = + let + deviceClass : DeviceClass + deviceClass = + Phone + + --Replace this line to make the layout responsive + --Layout.getDeviceClass window + dialog : Maybe (Modal Msg) + dialog = + if showDialog then + { text = "This is a dialog window" + , title = Just "Dialog" + , accept = Nothing + , dismiss = + Just + { text = "Accept" + , onPress = + Just <| + ShowDialog False + } + } + |> Widget.dialog (Material.alertDialog palette) + |> Just + + else + Nothing + + menu = + { selected = Just selected + , options = + [ "Home", "About" ] + |> List.map + (\string -> + { text = string + , icon = always Element.none + } + ) + , onSelect = SetSelected >> Just + } + + actions = + { icon = + MaterialIcons.change_history + |> Icon.elmMaterialIcons Color + , text = "Action" + , onPress = Nothing + } + |> List.repeat 5 + + { primaryActions, moreActions } = + Layout.partitionActions actions + + titleEl = + "Title" + |> Element.text + |> Element.el (Typography.h6 ++ [ Element.paddingXY 8 0 ]) + + search : TextInput Msg + search = + { chips = [] + , text = searchText + , placeholder = Nothing + , label = "Search" + , onChange = SetSearchText + } + + nav : Element Msg + nav = + if + (deviceClass == Phone) + || (deviceClass == Tablet) + || (menu.options |> List.length) + > 5 + then + Widget.menuBar (Material.menuBar palette) + { title = titleEl + , deviceClass = deviceClass + , openLeftSheet = Just <| ChangedSidebar <| Just LeftSheet + , openRightSheet = Just <| ChangedSidebar <| Just RightSheet + , openTopSheet = Just <| ChangedSidebar <| Just Search + , primaryActions = primaryActions + , search = Just search + } + + else + Widget.tabBar (Material.tabBar palette) + { title = titleEl + , menu = menu + , deviceClass = deviceClass + , openRightSheet = Just <| ChangedSidebar <| Just RightSheet + , openTopSheet = Nothing + , primaryActions = primaryActions + , search = Just search + } + + snackbarElem : Element Msg + snackbarElem = + snackbar + |> Snackbar.view (Material.snackbar palette) + (\text -> + { text = text + , button = Nothing + } + ) + |> Maybe.map + (Element.el + [ Element.padding 8 + , Element.alignBottom + , Element.alignRight + ] + ) + |> Maybe.withDefault Element.none + + onDismiss = + Nothing + |> ChangedSidebar + + modals = + Layout.orderModals + { dialog = dialog + , leftSheet = + if active == Just LeftSheet then + Layout.leftSheet + { button = Material.selectItem palette + , sheet = Material.sideSheet palette + } + { title = titleEl + , menu = menu + , onDismiss = onDismiss + } + |> Just + + else + Nothing + , rightSheet = + if active == Just RightSheet then + Layout.rightSheet + { sheet = Material.sideSheet palette + , insetItem = Material.insetItem palette + } + { onDismiss = onDismiss + , moreActions = moreActions + } + |> Just + + else + Nothing + , topSheet = + if active == Just Search then + Layout.searchSheet (searchFill palette) + { search = search + , onDismiss = onDismiss + } + |> Just + + else + Nothing + , bottomSheet = Nothing + } + in + [ nav + , Widget.button (Material.containedButton palette) + { onPress = Just <| AddSnackbar + , text = "Add Notification" + , icon = always Element.none + } + ] + |> Element.column [ Element.width <| Element.fill, Element.spacing 8 ] + |> Element.el + (List.concat + [ container palette + , [ Element.inFront snackbarElem ] + , modals + |> Widget.singleModal + , [ Element.height <| Element.minimum 200 <| Element.fill + , Element.width <| Element.minimum 400 <| Element.fill + ] + ] + ) + + + +-------------------------------------------------------------------------------- +-- DO NOT MODIFY ANYTHING AFTER THIS LINE +-------------------------------------------------------------------------------- + + +demo : Tile Model Msg () +demo = + { init = always init + , update = update + , view = Page.demo view + , subscriptions = subscriptions + } + + +page = + Page.create + { title = title + , description = description + , book = book + , demo = demo + } From 1564af7e66476c1ee592ceff7a6d78c812e5f284 Mon Sep 17 00:00:00 2001 From: Lucas Payr Date: Tue, 8 Jun 2021 14:11:54 +0200 Subject: [PATCH 5/5] Add Icon Page --- explorer/elm.json | 8 ++ explorer/src/Main.elm | 2 + explorer/src/Page/Icon.elm | 164 ++++++++++++++++++++++++++++++++++++ explorer/src/UIExplorer.elm | 1 + 4 files changed, 175 insertions(+) create mode 100644 explorer/src/Page/Icon.elm diff --git a/explorer/elm.json b/explorer/elm.json index b1d08b1..1d9c0fb 100644 --- a/explorer/elm.json +++ b/explorer/elm.json @@ -8,6 +8,8 @@ "dependencies": { "direct": { "avh4/elm-color": "1.0.0", + "capitalist/elm-octicons": "2.3.0", + "danmarcab/material-icons": "1.0.0", "elm/browser": "1.0.2", "elm/core": "1.0.5", "elm/html": "1.0.0", @@ -16,12 +18,18 @@ "elm/time": "1.0.0", "elm/url": "1.0.0", "elm-explorations/markdown": "1.0.0", + "feathericons/elm-feather": "1.5.0", "ianmackenzie/elm-units": "2.9.0", "icidasset/elm-material-icons": "8.0.0", "insurello/elm-ui-explorer": "2.0.0", + "j-panasiuk/elm-ionicons": "2.0.0", + "jasonliang-dev/elm-heroicons": "1.0.3", + "lattyware/elm-fontawesome": "5.0.0", + "lemol/ant-design-icons-elm": "2.0.0", "mdgriffith/elm-ui": "1.1.7", "miyamoen/select-list": "4.1.0", "noahzgordon/elm-color-extra": "1.0.2", + "pehota/elm-zondicons": "1.0.1", "turboMaCk/queue": "1.1.0", "zwilias/elm-rosetree": "1.5.0" }, diff --git a/explorer/src/Main.elm b/explorer/src/Main.elm index f8e5152..36780f1 100644 --- a/explorer/src/Main.elm +++ b/explorer/src/Main.elm @@ -14,6 +14,7 @@ import Page.SortTable import Page.Switch import Page.Tab import Page.TextInput +import Page.Icon import UIExplorer @@ -31,6 +32,7 @@ pages = |> UIExplorer.nextPage "ProgressIndicator" Page.ProgressIndicator.page |> UIExplorer.nextPage "Modal" Page.Modal.page |> UIExplorer.nextPage "Layout" Page.Layout.page + |> UIExplorer.nextPage "Icon" Page.Icon.page main = diff --git a/explorer/src/Page/Icon.elm b/explorer/src/Page/Icon.elm new file mode 100644 index 0000000..bf8edd9 --- /dev/null +++ b/explorer/src/Page/Icon.elm @@ -0,0 +1,164 @@ +module Page.Icon exposing (page) + +{-| This is an example Page. If you want to add your own pages, simple copy and modify this one. +-} + +import Ant.Icons.Svg +import Browser +import Element exposing (Element) +import Element.Background as Background +import FeatherIcons +import FontAwesome.Solid +import FontAwesome.Svg +import Heroicons.Solid +import Ionicon +import Material.Icons +import Material.Icons.Action +import Material.Icons.Types exposing (Coloring(..)) +import Octicons +import Page +import UIExplorer.Story as Story exposing (StorySelectorModel, StorySelectorMsg) +import UIExplorer.Tile as Tile exposing (Context, Tile, TileMsg) +import Widget exposing (ButtonStyle, RowStyle) +import Widget.Customize as Customize +import Widget.Icon +import Widget.Material as Material +import Widget.Material.Color as MaterialColor +import Widget.Material.Typography as Typography +import Zondicons + + +{-| The title of this page +-} +title : String +title = + "Icon" + + +{-| The description. I've taken this description directly from the [Material-UI-Specification](https://material.io/components/buttons) +-} +description : String +description = + "Every icon package on elm-packages is supported." + + + + + +{- This next section is essentially just a normal Elm program. -} +-------------------------------------------------------------------------------- +-- Interactive Demonstration +-------------------------------------------------------------------------------- + + +type alias Model = + () + + +type alias Msg = + () + + +init : ( Model, Cmd Msg ) +init = + ( () + , 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 : Context -> Model -> Element Msg +view { palette } () = + [ ( Material.Icons.done + |> Widget.Icon.elmMaterialIcons Color + , "elm-material-icons" + ) + , ( Material.Icons.Action.done + |> Widget.Icon.materialIcons + , "material-icons" + ) + , ( FeatherIcons.check + |> Widget.Icon.elmFeather FeatherIcons.toHtml + , "elm-feather" + ) + , ( FontAwesome.Solid.check + |> Widget.Icon.elmFontawesome FontAwesome.Svg.viewIcon + , "elm-fontawesome" + ) + , ( Ionicon.checkmark + |> Widget.Icon.elmIonicons + , "elm-ionicons" + ) + , ( Octicons.check + |> Widget.Icon.elmOcticons + { withSize = Octicons.size + , withColor = Octicons.color + , defaultOptions = Octicons.defaultOptions + } + , "elm-octicons" + ) + , ( Heroicons.Solid.check + |> Widget.Icon.elmHeroicons + , "elm-heroicons" + ) + , ( Ant.Icons.Svg.checkOutlined + |> Widget.Icon.antDesignIconsElm + , "ant-design-icons-elm" + ) + , ( Zondicons.checkmark + |> Widget.Icon.elmZondicons + , "elm-zondicons" + ) + ] + |> List.map + (\( icon, text ) -> + Widget.button (Material.containedButton palette) + { text = text + , icon = icon + , onPress = Just () + } + ) + |> Element.wrappedRow [ Element.spacing 10 ] + + + +-------------------------------------------------------------------------------- +-- DO NOT MODIFY ANYTHING AFTER THIS LINE +-------------------------------------------------------------------------------- + + +demo : Tile Model Msg () +demo = + { init = always init + , update = update + , view = Page.demo view + , subscriptions = subscriptions + } + + +page = + Tile.static [] + (\_ _ -> + [ title |> Element.text |> Element.el Typography.h3 + , description |> Element.text |> List.singleton |> Element.paragraph [] + ] + |> Element.column [ Element.spacing 32 ] + ) + |> Tile.first + |> Tile.next demo + |> Tile.page diff --git a/explorer/src/UIExplorer.elm b/explorer/src/UIExplorer.elm index 6be9dd7..7a48c83 100644 --- a/explorer/src/UIExplorer.elm +++ b/explorer/src/UIExplorer.elm @@ -701,6 +701,7 @@ viewSuccess config ((PageBuilder pages) as pages_) model = :: Element.inFront (Element.el [ Element.height <| Element.px (Pixels.inPixels model.windowSize.height) + , Element.scrollbarY , Element.Font.size 16 ] (viewSidebar pages_ config model)