diff --git a/explorer/elm.json b/explorer/elm.json index 2c609c9..b1d08b1 100644 --- a/explorer/elm.json +++ b/explorer/elm.json @@ -13,6 +13,7 @@ "elm/html": "1.0.0", "elm/json": "1.1.3", "elm/svg": "1.0.1", + "elm/time": "1.0.0", "elm/url": "1.0.0", "elm-explorations/markdown": "1.0.0", "ianmackenzie/elm-units": "2.9.0", @@ -26,7 +27,6 @@ }, "indirect": { "elm/regex": "1.0.0", - "elm/time": "1.0.0", "elm/virtual-dom": "1.0.2", "fredcy/elm-parseint": "2.0.1" } diff --git a/explorer/src/Main.elm b/explorer/src/Main.elm index 6398efe..62abc82 100644 --- a/explorer/src/Main.elm +++ b/explorer/src/Main.elm @@ -4,8 +4,11 @@ import Element import Page.Button import Page.PasswordInput import Page.Select +import Page.Snackbar +import Page.SortTable import Page.Switch import Page.Tab +import Page.TextInput import UIExplorer @@ -15,6 +18,9 @@ pages = |> UIExplorer.nextPage "Switch" Page.Switch.page |> UIExplorer.nextPage "Tab" Page.Tab.page |> UIExplorer.nextPage "Password Input" Page.PasswordInput.page + |> UIExplorer.nextPage "Text Input" Page.TextInput.page + |> UIExplorer.nextPage "Sort Table" Page.SortTable.page + |> UIExplorer.nextPage "Snackbar" Page.Snackbar.page main = diff --git a/explorer/src/Page.elm b/explorer/src/Page.elm index 0295f89..ea10b94 100644 --- a/explorer/src/Page.elm +++ b/explorer/src/Page.elm @@ -1,4 +1,4 @@ -module Page exposing (create, demo, viewTile) +module Page exposing (create, create2, demo, viewTile) import Element exposing (Element) import UIExplorer exposing (Page) @@ -35,6 +35,29 @@ create config = |> Tile.page +create2 : + { title : String + , description : String + , book1 : Group ( StorySelectorModel, () ) (TileMsg StorySelectorMsg ()) () + , book2 : Group ( StorySelectorModel, () ) (TileMsg StorySelectorMsg ()) () + , demo : Tile model msg () + } + -> Page ( ( ( ( (), () ), ( StorySelectorModel, () ) ), ( StorySelectorModel, () ) ), model ) (TileMsg (TileMsg (TileMsg (TileMsg () msg1) (TileMsg StorySelectorMsg ())) (TileMsg StorySelectorMsg ())) msg) () +create2 config = + Tile.static [] + (\_ _ -> + [ config.title |> Element.text |> Element.el Typography.h3 + , config.description |> Element.text |> List.singleton |> Element.paragraph [] + ] + |> Element.column [ Element.spacing 32 ] + ) + |> Tile.first + |> Tile.nextGroup config.book1 + |> Tile.nextGroup config.book2 + |> Tile.next config.demo + |> Tile.page + + viewTile : String -> Element msg diff --git a/explorer/src/Page/PasswordInput.elm b/explorer/src/Page/PasswordInput.elm index f9019b4..f1ac450 100644 --- a/explorer/src/Page/PasswordInput.elm +++ b/explorer/src/Page/PasswordInput.elm @@ -32,24 +32,24 @@ description = -} viewFunctions = let - viewCurrentPassword text placeholder label { palette } () = + viewCurrentPassword text placeholder label show { palette } () = Widget.currentPasswordInput (Material.passwordInput palette) { text = text , placeholder = placeholder , label = label , onChange = always () - , show = False + , show = show } --Don't forget to change the title |> Page.viewTile "Widget.currentPasswordInput" - viewNewPassword text placeholder label { palette } () = + viewNewPassword text placeholder label show { palette } () = Widget.newPasswordInput (Material.passwordInput palette) { text = text , placeholder = placeholder , label = label , onChange = always () - , show = False + , show = show } --Don't forget to change the title |> Page.viewTile "Widget.newPasswordInput" @@ -80,6 +80,13 @@ book = (Story.textStory "Label" "Password" ) + |> Story.addStory + (Story.boolStory "Show" + ( True + , False + ) + True + ) |> Story.build @@ -127,7 +134,7 @@ subscriptions _ = view : Context -> Model -> Element Msg view { palette } model = - [ "Try fill out these fields using autofill" |> Element.text + [ "Try filling out these fields using autofill" |> Element.text , [ "Current Password" |> Element.text |> Element.el [ Element.width <| Element.fill ] diff --git a/explorer/src/Page/Snackbar.elm b/explorer/src/Page/Snackbar.elm new file mode 100644 index 0000000..f842a1d --- /dev/null +++ b/explorer/src/Page/Snackbar.elm @@ -0,0 +1,223 @@ +module Page.Snackbar 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 Time +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 +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 + viewSnackbar style text button { palette } () = + Snackbar.view (style palette) + identity + (Snackbar.init + |> Snackbar.insert + { text = text + , button = button + } + ) + |> Maybe.withDefault Element.none + --Don't forget to change the title + |> Page.viewTile "Snackbar.view" + in + [ viewSnackbar ] + |> 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" + ( "Snackbar", Material.snackbar ) + [] + ) + --Changing the text of the label + |> Story.addStory + (Story.textStory "Text" + "This is a notification that will close after 10 seconds. Additional notifications are being queued." + ) + --Change the Icon + |> Story.addStory + (Story.optionListStory "Button" + ( "Button with event handler" + , Just + { text = "Close" + , onPress = Just () + } + ) + [ ( "Eventless Button" + , Just + { text = "Close" + , onPress = Nothing + } + ) + , ( "None" + , Nothing + ) + ] + ) + |> Story.build + + + +{- This next section is essentially just a normal Elm program. -} +-------------------------------------------------------------------------------- +-- Interactive Demonstration +-------------------------------------------------------------------------------- + + +type alias Model = + Snackbar ( String, Bool ) + + +type Msg + = AddSnackbar ( String, Bool ) + | TimePassed Int + + +init : ( Model, Cmd Msg ) +init = + ( Snackbar.init + , Cmd.none + ) + + +update : Msg -> Model -> ( Model, Cmd Msg ) +update msg model = + case msg of + TimePassed int -> + ( model |> Snackbar.timePassed int + , Cmd.none + ) + + AddSnackbar snack -> + ( model |> Snackbar.dismiss |> Snackbar.insert snack + , Cmd.none + ) + + +subscriptions : Model -> Sub Msg +subscriptions _ = + 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 } model = + [ Widget.button (Material.containedButton palette) + { onPress = + Just <| + AddSnackbar <| + ( "This is a notification. It will disappear after 10 seconds." + , False + ) + , text = "Add Notification" + , icon = always Element.none + } + , Widget.button (Material.containedButton palette) + { onPress = + Just <| + AddSnackbar <| + ( "You can add another notification if you want." + , True + ) + , text = "Add Notification with Action" + , icon = always Element.none + } + ] + |> Widget.column Material.column + |> Element.el + [ Element.height <| Element.minimum 200 <| Element.fill + , Element.width <| Element.minimum 400 <| Element.fill + , Element.inFront <| + (model + |> Snackbar.view (Material.snackbar palette) + (\( text, hasButton ) -> + { text = text + , button = + if hasButton then + Just + { text = "Add" + , onPress = + Just <| + AddSnackbar ( "This is another message", False ) + } + + else + Nothing + } + ) + |> Maybe.map + (Element.el + [ Element.padding 8 + , Element.alignBottom + , Element.alignRight + ] + ) + |> Maybe.withDefault Element.none + ) + ] + + + +-------------------------------------------------------------------------------- +-- 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/SortTable.elm b/explorer/src/Page/SortTable.elm new file mode 100644 index 0000000..deec963 --- /dev/null +++ b/explorer/src/Page/SortTable.elm @@ -0,0 +1,250 @@ +module Page.SortTable 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 (SortTableStyle) +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 = + "Sort Table" + + +{-| The description. I've taken this description directly from the [Material-UI-Specification](https://material.io/components/buttons) +-} +description : String +description = + "A simple sort table." + + +{-| List of view functions. Essentially, anything that takes a Button as input. +-} +viewFunctions = + let + viewTable style content columns asc sortBy { palette } () = + Widget.sortTable (style palette) + { content = content + , columns = columns + , asc = asc + , sortBy = sortBy + , onChange = always () + } + --Don't forget to change the title + |> Page.viewTile "Widget.sortTable" + in + [ viewTable ] + |> 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" + ( "SortTable", Material.sortTable ) + [] + ) + |> Story.addStory + (Story.optionListStory "Content" + ( "Data" + , [ { 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" } + ] + ) + [ ( "None", [] ) + ] + ) + --Changing the text of the label + |> Story.addStory + (Story.optionListStory "Columns" + ( "4 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 + } + ] + ) + [ ( "1 Column" + , [ Widget.intColumn + { title = "Id" + , value = .id + , toString = \int -> "#" ++ String.fromInt int + , width = Element.fill + } + ] + ) + , ( "None", [] ) + ] + ) + --Change the Icon + |> Story.addStory + (Story.boolStory "Sort ascendingly" + ( True + , False + ) + True + ) + |> Story.addStory + (Story.optionListStory "Sort by" + ( "Id", "Id" ) + [ ( "Name", "Name" ) + , ( "Rating", "Rating" ) + , ( "Hash", "Hash" ) + , ( "None", "" ) + ] + ) + |> Story.build + + + +{- This next section is essentially just a normal Elm program. -} +-------------------------------------------------------------------------------- +-- Interactive Demonstration +-------------------------------------------------------------------------------- + + +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 + + +{-| 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 } model = + Widget.sortTable (Material.sortTable palette) + { 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 + } + + + +-------------------------------------------------------------------------------- +-- 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/TextInput.elm b/explorer/src/Page/TextInput.elm new file mode 100644 index 0000000..468b41a --- /dev/null +++ b/explorer/src/Page/TextInput.elm @@ -0,0 +1,214 @@ +module Page.TextInput exposing (Model, Msg, init, page, subscriptions, update, view) + +import Element exposing (Element) +import Element.Input as Input +import Material.Icons as MaterialIcons +import Material.Icons.Types exposing (Coloring(..)) +import Page +import Set exposing (Set) +import UIExplorer.Story as Story +import UIExplorer.Tile exposing (Context, Tile) +import Widget +import Widget.Icon as Icon exposing (Icon) +import Widget.Material as Material + exposing + ( darkPalette + , defaultPalette + ) + + +{-| The title of this page +-} +title : String +title = + "Text Input" + + +{-| The description. I've taken this description directly from the [Material-UI-Specification](https://material.io/components/buttons) +-} +description : String +description = + "Text fields let users enter and edit text." + + +{-| List of view functions. Essentially, anything that takes a Button as input. +-} +viewFunctions = + let + viewInput chips text placeholder label { palette } () = + Widget.textInput (Material.textInput palette) + { chips = chips + , text = text + , placeholder = placeholder + , label = label + , onChange = always () + } + --Don't forget to change the title + |> Page.viewTile "Widget.currentPasswordInput" + in + [ viewInput ] + |> List.foldl Story.addTile + Story.initStaticTiles + + +book = + Story.book (Just "Options") + viewFunctions + |> Story.addStory + (Story.optionListStory "Chips" + ( "3 Chips" + , [ { icon = always Element.none, text = "Apples", onPress = Nothing } + , { icon = MaterialIcons.done |> Icon.elmMaterialIcons Color, text = "", onPress = Just () } + , { icon = MaterialIcons.done |> Icon.elmMaterialIcons Color, text = "Oranges", onPress = Just () } + ] + ) + [ ( "2 Chips" + , [ { icon = always Element.none, text = "Apples", onPress = Nothing } + , { icon = MaterialIcons.done |> Icon.elmMaterialIcons Color, text = "", onPress = Just () } + ] + ) + , ( "1 Chips" + , [ { icon = always Element.none, text = "Apples", onPress = Nothing } ] + ) + , ( "None", [] ) + ] + ) + |> Story.addStory + (Story.textStory "Text" + "123456789" + ) + |> Story.addStory + (Story.boolStory "Placeholder" + ( "password" + |> Element.text + |> Input.placeholder [] + |> Just + , Nothing + ) + True + ) + |> Story.addStory + (Story.textStory "Label" + "Name" + ) + |> Story.build + + + +---{- This next section is essentially just a normal Elm program. -} +----------------------------------------------------------------------------- +-- Interactive Demonstration +-------------------------------------------------------------------------------- + + +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 : Context -> Model -> Element Msg +view { palette } model = + [ { chips = + model.chipTextInput + |> Set.toList + |> List.map + (\string -> + { icon = always Element.none + , text = string + , onPress = + string + |> ToggleTextInputChip + |> Just + } + ) + , text = model.textInput + , placeholder = Nothing + , label = "Chips" + , onChange = SetTextInput + } + |> Widget.textInput (Material.textInput palette) + , model.chipTextInput + |> Set.diff + ([ "A", "B", "C" ] + |> Set.fromList + ) + |> Set.toList + |> List.map + (\string -> + Widget.button (Material.textInput palette).content.chips.content + { onPress = + string + |> ToggleTextInputChip + |> Just + , text = string + , icon = always Element.none + } + ) + |> Element.wrappedRow [ Element.spacing 10 ] + ] + |> Widget.column Material.column + + + +-------------------------------------------------------------------------------- +-- 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/UIExplorer.elm b/explorer/src/UIExplorer.elm index 059d19d..f954f82 100644 --- a/explorer/src/UIExplorer.elm +++ b/explorer/src/UIExplorer.elm @@ -864,8 +864,6 @@ viewSidebar pages config model = |> Widget.itemList (Material.sideSheet palette) - - colorblindnessCss : Html msg colorblindnessCss = Html.node "style" @@ -1118,8 +1116,6 @@ optionGroupView dark isExpanded selectedItem items itemToString onPress toggleEx } - - showSearchResults : String -> Bool showSearchResults searchText = String.length searchText > 1