mirror of
https://github.com/NoRedInk/noredink-ui.git
synced 2024-11-24 17:02:51 +03:00
Add Button.V6 to use Icon.V4
This commit is contained in:
parent
be8047e1de
commit
ed62cd4f5a
@ -18,6 +18,7 @@
|
|||||||
"Nri.Ui.Button.V3",
|
"Nri.Ui.Button.V3",
|
||||||
"Nri.Ui.Button.V4",
|
"Nri.Ui.Button.V4",
|
||||||
"Nri.Ui.Button.V5",
|
"Nri.Ui.Button.V5",
|
||||||
|
"Nri.Ui.Button.V6",
|
||||||
"Nri.Ui.Checkbox.V1",
|
"Nri.Ui.Checkbox.V1",
|
||||||
"Nri.Ui.Checkbox.V2",
|
"Nri.Ui.Checkbox.V2",
|
||||||
"Nri.Ui.Checkbox.V3",
|
"Nri.Ui.Checkbox.V3",
|
||||||
|
1722
package-lock.json
generated
1722
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
813
src/Nri/Ui/Button/V6.elm
Normal file
813
src/Nri/Ui/Button/V6.elm
Normal file
@ -0,0 +1,813 @@
|
|||||||
|
module Nri.Ui.Button.V6 exposing
|
||||||
|
( ButtonSize(..), ButtonWidth(..), ButtonStyle(..), ButtonState(..), ButtonContent
|
||||||
|
, ButtonConfig, button, customButton, delete, copyToClipboard, ToggleButtonConfig, toggleButton
|
||||||
|
, LinkConfig, link, linkSpa, linkExternal, linkWithMethod, linkWithTracking, linkExternalWithTracking
|
||||||
|
)
|
||||||
|
|
||||||
|
{-|
|
||||||
|
|
||||||
|
|
||||||
|
# Changes from V5:
|
||||||
|
|
||||||
|
- Update version of Nri.Ui.Icon to V4
|
||||||
|
|
||||||
|
|
||||||
|
# About:
|
||||||
|
|
||||||
|
Common NoRedInk buttons. For accessibility purposes, buttons that perform an
|
||||||
|
action on the current page should be HTML `<button>` elements and are created here
|
||||||
|
with `*Button` functions. Buttons that take the user to a new page should be
|
||||||
|
HTML `<a>` elements and are created here with `*Link` functions. Both versions
|
||||||
|
should be able to use the same CSS class in all cases.
|
||||||
|
|
||||||
|
There will generally be a `*Button` and `*Link` version of each button style.
|
||||||
|
(These will be created as they are needed.)
|
||||||
|
|
||||||
|
In general a button should never truncate or obscure its contents. This could
|
||||||
|
make it difficult or impossible for a student or teacher to use the site, so in
|
||||||
|
general choose buttons that grow to fit their contents. It is better to risk
|
||||||
|
weird layout than to block users. Might this be a golden rule? Of course there
|
||||||
|
may be exceptions, for example if button content is supplied by an end-user.
|
||||||
|
|
||||||
|
|
||||||
|
## Common configs
|
||||||
|
|
||||||
|
@docs ButtonSize, ButtonWidth, ButtonStyle, ButtonState, ButtonContent
|
||||||
|
|
||||||
|
|
||||||
|
## `<button>` Buttons
|
||||||
|
|
||||||
|
@docs ButtonConfig, button, customButton, delete, copyToClipboard, ToggleButtonConfig, toggleButton
|
||||||
|
|
||||||
|
|
||||||
|
## `<a>` Buttons
|
||||||
|
|
||||||
|
@docs LinkConfig, link, linkSpa, linkExternal, linkWithMethod, linkWithTracking, linkExternalWithTracking
|
||||||
|
|
||||||
|
-}
|
||||||
|
|
||||||
|
import Accessibility.Styled as Html exposing (Attribute, Html)
|
||||||
|
import Accessibility.Styled.Role as Role
|
||||||
|
import Accessibility.Styled.Widget as Widget
|
||||||
|
import Css exposing (Style)
|
||||||
|
import Css.Foreign
|
||||||
|
import EventExtras.Styled as EventExtras
|
||||||
|
import Html.Styled as Styled
|
||||||
|
import Html.Styled.Attributes as Attributes
|
||||||
|
import Html.Styled.Events as Events
|
||||||
|
import Json.Decode
|
||||||
|
import Markdown.Block
|
||||||
|
import Markdown.Inline
|
||||||
|
import Nri.Ui
|
||||||
|
import Nri.Ui.AssetPath as AssetPath exposing (Asset)
|
||||||
|
import Nri.Ui.Colors.Extra as ColorsExtra
|
||||||
|
import Nri.Ui.Colors.V1 as Colors
|
||||||
|
import Nri.Ui.Fonts.V1
|
||||||
|
import Nri.Ui.Icon.V4 as Icon exposing (IconType)
|
||||||
|
|
||||||
|
|
||||||
|
{-| Sizes for buttons and links that have button classes
|
||||||
|
-}
|
||||||
|
type ButtonSize
|
||||||
|
= Small
|
||||||
|
| Medium
|
||||||
|
| Large
|
||||||
|
|
||||||
|
|
||||||
|
{-| Width sizing behavior for buttons.
|
||||||
|
|
||||||
|
`WidthExact Int` defines a size in `px` for the button's total width, and
|
||||||
|
`WidthUnbounded` leaves the maxiumum width unbounded (there is a minimum width).
|
||||||
|
|
||||||
|
-}
|
||||||
|
type ButtonWidth
|
||||||
|
= WidthExact Int
|
||||||
|
| WidthUnbounded
|
||||||
|
|
||||||
|
|
||||||
|
{-| Styleguide-approved styles for your buttons!
|
||||||
|
|
||||||
|
Note on borderless buttons:
|
||||||
|
A borderless button that performs an action on the current page
|
||||||
|
This button is intended to look like a link.
|
||||||
|
Only use a borderless button when the clickable text in question follows the same layout/margin/padding as a bordered button
|
||||||
|
|
||||||
|
-}
|
||||||
|
type ButtonStyle
|
||||||
|
= Primary
|
||||||
|
| Secondary
|
||||||
|
| Borderless
|
||||||
|
| Danger
|
||||||
|
| Premium
|
||||||
|
|
||||||
|
|
||||||
|
{-| Describes the state of a button. Has consequences for appearance and disabled attribute.
|
||||||
|
|
||||||
|
- Enabled: An enabled button. Takes the appearance of ButtonStyle
|
||||||
|
- Unfulfilled: A button which appears with the InactiveColors palette but is not disabled.
|
||||||
|
- Disabled: A button which appears with the InactiveColors palette and is disabled.
|
||||||
|
- Error: A button which appears with the ErrorColors palette and is disabled.
|
||||||
|
- Loading: A button which appears with the LoadingColors palette and is disabled
|
||||||
|
- Success: A button which appears with the SuccessColors palette and is disabled
|
||||||
|
|
||||||
|
-}
|
||||||
|
type ButtonState
|
||||||
|
= Enabled
|
||||||
|
| Unfulfilled
|
||||||
|
| Disabled
|
||||||
|
| Error
|
||||||
|
| Loading
|
||||||
|
| Success
|
||||||
|
|
||||||
|
|
||||||
|
{-| The part of a button that remains constant through different button states
|
||||||
|
-}
|
||||||
|
type alias ButtonConfig msg =
|
||||||
|
{ onClick : msg
|
||||||
|
, size : ButtonSize
|
||||||
|
, style : ButtonStyle
|
||||||
|
, width : ButtonWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
{-| ButtonContent, often changes based on ButtonState. For example, a button in the "Success"
|
||||||
|
state may have a different label than a button in the "Error" state
|
||||||
|
-}
|
||||||
|
type alias ButtonContent =
|
||||||
|
{ label : String
|
||||||
|
, state : ButtonState
|
||||||
|
, icon : Maybe IconType
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
{-| A delightful button which can trigger an effect when clicked!
|
||||||
|
|
||||||
|
This button will trigger the passed-in message if the button state is:
|
||||||
|
|
||||||
|
- Enabled
|
||||||
|
- Unfulfilled
|
||||||
|
|
||||||
|
This button will be Disabled if the button state is:
|
||||||
|
|
||||||
|
- Disabled
|
||||||
|
- Error
|
||||||
|
- Loading
|
||||||
|
- Success
|
||||||
|
|
||||||
|
-}
|
||||||
|
button : ButtonConfig msg -> ButtonContent -> Html msg
|
||||||
|
button config content =
|
||||||
|
customButton [] config content
|
||||||
|
|
||||||
|
|
||||||
|
{-| Exactly the same as button but you can pass in a list of attributes
|
||||||
|
-}
|
||||||
|
customButton : List (Attribute msg) -> ButtonConfig msg -> ButtonContent -> Html msg
|
||||||
|
customButton attributes config content =
|
||||||
|
let
|
||||||
|
buttonStyle =
|
||||||
|
case content.state of
|
||||||
|
Enabled ->
|
||||||
|
styleToColorPalette config.style
|
||||||
|
|
||||||
|
Disabled ->
|
||||||
|
InactiveColors
|
||||||
|
|
||||||
|
Error ->
|
||||||
|
ErrorColors
|
||||||
|
|
||||||
|
Unfulfilled ->
|
||||||
|
InactiveColors
|
||||||
|
|
||||||
|
Loading ->
|
||||||
|
LoadingColors
|
||||||
|
|
||||||
|
Success ->
|
||||||
|
SuccessColors
|
||||||
|
|
||||||
|
disabled =
|
||||||
|
case content.state of
|
||||||
|
Enabled ->
|
||||||
|
False
|
||||||
|
|
||||||
|
Disabled ->
|
||||||
|
True
|
||||||
|
|
||||||
|
Error ->
|
||||||
|
True
|
||||||
|
|
||||||
|
Unfulfilled ->
|
||||||
|
False
|
||||||
|
|
||||||
|
Loading ->
|
||||||
|
True
|
||||||
|
|
||||||
|
Success ->
|
||||||
|
True
|
||||||
|
in
|
||||||
|
Nri.Ui.styled Html.button
|
||||||
|
(styledName "customButton")
|
||||||
|
[ buttonStyles config.size config.width buttonStyle ]
|
||||||
|
([ Events.onClick config.onClick
|
||||||
|
, Attributes.disabled disabled
|
||||||
|
, Attributes.type_ "button"
|
||||||
|
]
|
||||||
|
++ attributes
|
||||||
|
)
|
||||||
|
[ viewLabel content.icon content.label ]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- COPY TO CLIPBOARD BUTTON
|
||||||
|
|
||||||
|
|
||||||
|
{-| Config for copyToClipboard
|
||||||
|
-}
|
||||||
|
type alias CopyToClipboardConfig =
|
||||||
|
{ size : ButtonSize
|
||||||
|
, style : ButtonStyle
|
||||||
|
, copyText : String
|
||||||
|
, buttonLabel : String
|
||||||
|
, withIcon : Bool
|
||||||
|
, width : ButtonWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
{-| See ui/src/Page/Teach/Courses/Assignments/index.coffee
|
||||||
|
You will need to hook this up to clipboard.js
|
||||||
|
-}
|
||||||
|
copyToClipboard : { r | teach_assignments_copyWhite_svg : Asset } -> CopyToClipboardConfig -> Html msg
|
||||||
|
copyToClipboard assets config =
|
||||||
|
let
|
||||||
|
maybeIcon =
|
||||||
|
if config.withIcon then
|
||||||
|
Just (Icon.copy assets)
|
||||||
|
|
||||||
|
else
|
||||||
|
Nothing
|
||||||
|
in
|
||||||
|
Nri.Ui.styled Html.button
|
||||||
|
(styledName "copyToClipboard")
|
||||||
|
[ buttonStyles config.size config.width (styleToColorPalette config.style) ]
|
||||||
|
[ Widget.label "Copy URL to clipboard"
|
||||||
|
, Attributes.attribute "data-clipboard-text" config.copyText
|
||||||
|
]
|
||||||
|
[ viewLabel maybeIcon config.buttonLabel ]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- DELETE BUTTON
|
||||||
|
|
||||||
|
|
||||||
|
type alias DeleteButtonConfig msg =
|
||||||
|
{ label : String
|
||||||
|
, onClick : msg
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
{-| A delete button (blue X)
|
||||||
|
-}
|
||||||
|
delete : { r | x : String } -> DeleteButtonConfig msg -> Html msg
|
||||||
|
delete assets config =
|
||||||
|
Nri.Ui.styled Html.button
|
||||||
|
(styledName "delete")
|
||||||
|
[ Css.display Css.inlineBlock
|
||||||
|
, Css.backgroundRepeat Css.noRepeat
|
||||||
|
, Css.backgroundColor Css.transparent
|
||||||
|
, Css.backgroundPosition Css.center
|
||||||
|
, Css.backgroundSize Css.contain
|
||||||
|
, Css.border Css.zero
|
||||||
|
, Css.width (Css.px 15)
|
||||||
|
, Css.height (Css.px 15)
|
||||||
|
, Css.padding Css.zero
|
||||||
|
, Css.margin2 Css.zero (Css.px 6)
|
||||||
|
, Css.cursor Css.pointer
|
||||||
|
, Css.color Colors.azure
|
||||||
|
]
|
||||||
|
[ Events.onClick config.onClick
|
||||||
|
, Attributes.type_ "button"
|
||||||
|
, -- reference: https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_button_role#Labeling_buttons
|
||||||
|
Widget.label config.label
|
||||||
|
]
|
||||||
|
[ Icon.icon { alt = "Delete", icon = Icon.xSvg assets } ]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- TOGGLE BUTTON
|
||||||
|
|
||||||
|
|
||||||
|
{-| Buttons can be toggled into a pressed state and back again.
|
||||||
|
-}
|
||||||
|
type alias ToggleButtonConfig msg =
|
||||||
|
{ label : String
|
||||||
|
, onSelect : msg
|
||||||
|
, onDeselect : msg
|
||||||
|
, pressed : Bool
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
{-| -}
|
||||||
|
toggleButton : ToggleButtonConfig msg -> Html msg
|
||||||
|
toggleButton config =
|
||||||
|
let
|
||||||
|
toggledStyles =
|
||||||
|
if config.pressed then
|
||||||
|
Css.batch
|
||||||
|
[ Css.color Colors.gray20
|
||||||
|
, Css.backgroundColor Colors.glacier
|
||||||
|
, Css.boxShadow5 Css.inset Css.zero (Css.px 3) Css.zero (ColorsExtra.withAlpha 0.2 Colors.gray20)
|
||||||
|
, Css.border3 (Css.px 1) Css.solid Colors.azure
|
||||||
|
, Css.fontWeight Css.bold
|
||||||
|
]
|
||||||
|
|
||||||
|
else
|
||||||
|
Css.batch
|
||||||
|
[]
|
||||||
|
in
|
||||||
|
Nri.Ui.styled Html.button
|
||||||
|
(styledName "toggleButton")
|
||||||
|
[ buttonStyles Medium WidthUnbounded SecondaryColors
|
||||||
|
, toggledStyles
|
||||||
|
]
|
||||||
|
[ Events.onClick
|
||||||
|
(if config.pressed then
|
||||||
|
config.onDeselect
|
||||||
|
|
||||||
|
else
|
||||||
|
config.onSelect
|
||||||
|
)
|
||||||
|
, Widget.pressed <| Just config.pressed
|
||||||
|
|
||||||
|
-- reference: https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_button_role#Labeling_buttons
|
||||||
|
, Role.button
|
||||||
|
|
||||||
|
-- Note: setting type: 'button' removes the default behavior of submit
|
||||||
|
-- equivalent to preventDefaultBehavior = false
|
||||||
|
-- https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-name
|
||||||
|
, Attributes.type_ "button"
|
||||||
|
]
|
||||||
|
[ viewLabel Nothing config.label ]
|
||||||
|
|
||||||
|
|
||||||
|
{-| Inputs can be a clickable thing used in a form
|
||||||
|
-}
|
||||||
|
type alias InputConfig =
|
||||||
|
{ content : Html Never
|
||||||
|
, name : String
|
||||||
|
, size : ButtonSize
|
||||||
|
, style : ButtonStyle
|
||||||
|
, value : String
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- LINKS THAT LOOK LIKE BUTTONS
|
||||||
|
|
||||||
|
|
||||||
|
{-| Links are clickable things with a url.
|
||||||
|
|
||||||
|
NOTE: Links do not support two-line labels.
|
||||||
|
|
||||||
|
-}
|
||||||
|
type alias LinkConfig =
|
||||||
|
{ label : String
|
||||||
|
, icon : Maybe IconType
|
||||||
|
, url : String
|
||||||
|
, size : ButtonSize
|
||||||
|
, style : ButtonStyle
|
||||||
|
, width : ButtonWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
{-| Wrap some text so it looks like a button, but actually is wrapped in an anchor to
|
||||||
|
some url
|
||||||
|
-}
|
||||||
|
link : LinkConfig -> Html msg
|
||||||
|
link =
|
||||||
|
linkBase "link" [ Attributes.target "_self" ]
|
||||||
|
|
||||||
|
|
||||||
|
{-| Use this link for routing within a single page app.
|
||||||
|
|
||||||
|
This will make a normal <a> tag, but change the Events.onClick behavior to avoid reloading the page.
|
||||||
|
|
||||||
|
See <https://github.com/elm-lang/html/issues/110> for details on this implementation.
|
||||||
|
|
||||||
|
-}
|
||||||
|
linkSpa :
|
||||||
|
(route -> String)
|
||||||
|
-> (route -> msg)
|
||||||
|
->
|
||||||
|
{ label : String
|
||||||
|
, icon : Maybe IconType
|
||||||
|
, size : ButtonSize
|
||||||
|
, style : ButtonStyle
|
||||||
|
, width : ButtonWidth
|
||||||
|
, route : route
|
||||||
|
}
|
||||||
|
-> Html msg
|
||||||
|
linkSpa toUrl toMsg config =
|
||||||
|
linkBase
|
||||||
|
"linkSpa"
|
||||||
|
[ EventExtras.onClickPreventDefaultForLinkWithHref (toMsg config.route)
|
||||||
|
]
|
||||||
|
{ label = config.label
|
||||||
|
, icon = config.icon
|
||||||
|
, size = config.size
|
||||||
|
, style = config.style
|
||||||
|
, width = config.width
|
||||||
|
, url = toUrl config.route
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
{-| Wrap some text so it looks like a button, but actually is wrapped in an anchor to
|
||||||
|
some url and have it open to an external site
|
||||||
|
-}
|
||||||
|
linkExternal : LinkConfig -> Html msg
|
||||||
|
linkExternal =
|
||||||
|
linkBase "linkExternal" [ Attributes.target "_blank" ]
|
||||||
|
|
||||||
|
|
||||||
|
{-| Wrap some text so it looks like a button, but actually is wrapped in an anchor to
|
||||||
|
some url, and it's an HTTP request (Rails includes JS to make this use the given HTTP method)
|
||||||
|
-}
|
||||||
|
linkWithMethod : String -> LinkConfig -> Html msg
|
||||||
|
linkWithMethod method =
|
||||||
|
linkBase "linkWithMethod" [ Attributes.attribute "data-method" method ]
|
||||||
|
|
||||||
|
|
||||||
|
{-| Wrap some text so it looks like a button, but actually is wrapped in an anchor to some url.
|
||||||
|
This should only take in messages that result in a Msg that triggers Analytics.trackAndRedirect. For buttons that trigger other effects on the page, please use Nri.Button.button instead
|
||||||
|
-}
|
||||||
|
linkWithTracking : msg -> LinkConfig -> Html msg
|
||||||
|
linkWithTracking onTrack =
|
||||||
|
linkBase
|
||||||
|
"linkWithTracking"
|
||||||
|
[ Events.onWithOptions "click"
|
||||||
|
{ stopPropagation = False
|
||||||
|
, preventDefault = True
|
||||||
|
}
|
||||||
|
(Json.Decode.succeed onTrack)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
{-| Wrap some text so it looks like a button, but actually is wrapped in an anchor to some url and have it open to an external site
|
||||||
|
|
||||||
|
This should only take in messages that result in tracking events. For buttons that trigger other effects on the page, please use Nri.Ui.Button.V2.button instead
|
||||||
|
|
||||||
|
-}
|
||||||
|
linkExternalWithTracking : msg -> LinkConfig -> Html msg
|
||||||
|
linkExternalWithTracking onTrack =
|
||||||
|
linkBase
|
||||||
|
"linkExternalWithTracking"
|
||||||
|
[ Attributes.target "_blank"
|
||||||
|
, EventExtras.onClickForLinkWithHref onTrack
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
{-| Helper function for building links with an arbitrary number of Attributes
|
||||||
|
-}
|
||||||
|
linkBase : String -> List (Attribute msg) -> LinkConfig -> Html msg
|
||||||
|
linkBase linkFunctionName extraAttrs config =
|
||||||
|
Nri.Ui.styled Styled.a
|
||||||
|
(styledName linkFunctionName)
|
||||||
|
[ buttonStyles config.size config.width (styleToColorPalette config.style) ]
|
||||||
|
(Attributes.href config.url
|
||||||
|
:: extraAttrs
|
||||||
|
)
|
||||||
|
[ viewLabel config.icon config.label ]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- HELPERS
|
||||||
|
|
||||||
|
|
||||||
|
type ColorPalette
|
||||||
|
= PrimaryColors
|
||||||
|
| SecondaryColors
|
||||||
|
| BorderlessColors
|
||||||
|
| DangerColors
|
||||||
|
| PremiumColors
|
||||||
|
| InactiveColors
|
||||||
|
| LoadingColors
|
||||||
|
| SuccessColors
|
||||||
|
| ErrorColors
|
||||||
|
|
||||||
|
|
||||||
|
styleToColorPalette : ButtonStyle -> ColorPalette
|
||||||
|
styleToColorPalette style =
|
||||||
|
case style of
|
||||||
|
Primary ->
|
||||||
|
PrimaryColors
|
||||||
|
|
||||||
|
Secondary ->
|
||||||
|
SecondaryColors
|
||||||
|
|
||||||
|
Borderless ->
|
||||||
|
BorderlessColors
|
||||||
|
|
||||||
|
Danger ->
|
||||||
|
DangerColors
|
||||||
|
|
||||||
|
Premium ->
|
||||||
|
PremiumColors
|
||||||
|
|
||||||
|
|
||||||
|
buttonStyles : ButtonSize -> ButtonWidth -> ColorPalette -> Style
|
||||||
|
buttonStyles size width colorPalette =
|
||||||
|
Css.batch
|
||||||
|
[ buttonStyle
|
||||||
|
, colorStyle colorPalette
|
||||||
|
, sizeStyle size width
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
viewLabel : Maybe IconType -> String -> Html msg
|
||||||
|
viewLabel icn label =
|
||||||
|
Nri.Ui.styled Html.span
|
||||||
|
"button-label-span"
|
||||||
|
[ Css.overflow Css.hidden -- Keep scrollbars out of our button
|
||||||
|
, Css.overflowWrap Css.breakWord -- Ensure that words that exceed the button width break instead of disappearing
|
||||||
|
, Css.padding2 (Css.px 2) Css.zero -- Without a bit of bottom padding, text that extends below the baseline, like "g" gets cut off
|
||||||
|
]
|
||||||
|
[]
|
||||||
|
(case icn of
|
||||||
|
Nothing ->
|
||||||
|
renderMarkdown label
|
||||||
|
|
||||||
|
Just iconType ->
|
||||||
|
Icon.decorativeIcon iconType :: renderMarkdown label
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
renderMarkdown : String -> List (Html msg)
|
||||||
|
renderMarkdown markdown =
|
||||||
|
case Markdown.Block.parse Nothing markdown of
|
||||||
|
-- It seems to be always first wrapped in a `Paragraph` and never directly a `PlainInline`
|
||||||
|
[ Markdown.Block.Paragraph _ inlines ] ->
|
||||||
|
List.map (Markdown.Inline.toHtml >> Styled.fromUnstyled) inlines
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
[ Html.text markdown ]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- STYLES
|
||||||
|
|
||||||
|
|
||||||
|
buttonStyle : Style
|
||||||
|
buttonStyle =
|
||||||
|
Css.batch
|
||||||
|
[ Css.cursor Css.pointer
|
||||||
|
, Css.display Css.inlineBlock
|
||||||
|
, -- Specifying the font can and should go away after bootstrap is removed from application.css
|
||||||
|
Nri.Ui.Fonts.V1.baseFont
|
||||||
|
, Css.textOverflow Css.ellipsis
|
||||||
|
, Css.overflow Css.hidden
|
||||||
|
, Css.textDecoration Css.none
|
||||||
|
, Css.backgroundImage Css.none
|
||||||
|
, Css.textShadow Css.none
|
||||||
|
, Css.property "transition" "background-color 0.2s, color 0.2s, box-shadow 0.2s, border 0.2s, border-width 0s"
|
||||||
|
, Css.boxShadow Css.none
|
||||||
|
, Css.border Css.zero
|
||||||
|
, Css.marginBottom Css.zero
|
||||||
|
, Css.hover [ Css.textDecoration Css.none ]
|
||||||
|
, Css.disabled [ Css.cursor Css.notAllowed ]
|
||||||
|
, Css.displayFlex
|
||||||
|
, Css.alignItems Css.center
|
||||||
|
, Css.justifyContent Css.center
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
colorStyle : ColorPalette -> Style
|
||||||
|
colorStyle colorPalette =
|
||||||
|
let
|
||||||
|
( config, additionalStyles ) =
|
||||||
|
case colorPalette of
|
||||||
|
PrimaryColors ->
|
||||||
|
( { background = Colors.azure
|
||||||
|
, hover = Colors.azureDark
|
||||||
|
, text = Colors.white
|
||||||
|
, border = Nothing
|
||||||
|
, shadow = Colors.azureDark
|
||||||
|
}
|
||||||
|
, []
|
||||||
|
)
|
||||||
|
|
||||||
|
SecondaryColors ->
|
||||||
|
( { background = Colors.white
|
||||||
|
, hover = Colors.glacier
|
||||||
|
, text = Colors.azure
|
||||||
|
, border = Just <| Colors.azure
|
||||||
|
, shadow = Colors.azure
|
||||||
|
}
|
||||||
|
, []
|
||||||
|
)
|
||||||
|
|
||||||
|
BorderlessColors ->
|
||||||
|
( { background = Css.rgba 0 0 0 0
|
||||||
|
, hover = Css.rgba 0 0 0 0
|
||||||
|
, text = Colors.azure
|
||||||
|
, border = Nothing
|
||||||
|
, shadow = Css.rgba 0 0 0 0
|
||||||
|
}
|
||||||
|
, [ Css.hover
|
||||||
|
[ Css.textDecoration Css.underline
|
||||||
|
, Css.disabled [ Css.textDecoration Css.none ]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
DangerColors ->
|
||||||
|
( { background = Colors.red
|
||||||
|
, hover = Colors.redDark
|
||||||
|
, text = Colors.white
|
||||||
|
, border = Nothing
|
||||||
|
, shadow = Colors.redDark
|
||||||
|
}
|
||||||
|
, []
|
||||||
|
)
|
||||||
|
|
||||||
|
PremiumColors ->
|
||||||
|
( { background = Colors.yellow
|
||||||
|
, hover = Colors.ochre
|
||||||
|
, text = Colors.navy
|
||||||
|
, border = Nothing
|
||||||
|
, shadow = Colors.ochre
|
||||||
|
}
|
||||||
|
, []
|
||||||
|
)
|
||||||
|
|
||||||
|
InactiveColors ->
|
||||||
|
( { background = Colors.gray92
|
||||||
|
, hover = Colors.gray92
|
||||||
|
, text = Colors.gray45
|
||||||
|
, border = Nothing
|
||||||
|
, shadow = Colors.gray92
|
||||||
|
}
|
||||||
|
, []
|
||||||
|
)
|
||||||
|
|
||||||
|
LoadingColors ->
|
||||||
|
( { background = Colors.glacier
|
||||||
|
, hover = Colors.glacier
|
||||||
|
, text = Colors.navy
|
||||||
|
, border = Nothing
|
||||||
|
, shadow = Colors.glacier
|
||||||
|
}
|
||||||
|
, []
|
||||||
|
)
|
||||||
|
|
||||||
|
SuccessColors ->
|
||||||
|
( { background = Colors.greenDark
|
||||||
|
, hover = Colors.greenDark
|
||||||
|
, text = Colors.white
|
||||||
|
, border = Nothing
|
||||||
|
, shadow = Colors.greenDark
|
||||||
|
}
|
||||||
|
, []
|
||||||
|
)
|
||||||
|
|
||||||
|
ErrorColors ->
|
||||||
|
( { background = Colors.purple
|
||||||
|
, hover = Colors.purple
|
||||||
|
, text = Colors.white
|
||||||
|
, border = Nothing
|
||||||
|
, shadow = Colors.purple
|
||||||
|
}
|
||||||
|
, []
|
||||||
|
)
|
||||||
|
in
|
||||||
|
Css.batch
|
||||||
|
[ Css.batch additionalStyles
|
||||||
|
, Css.color config.text
|
||||||
|
, Css.backgroundColor config.background
|
||||||
|
, Css.fontWeight (Css.int 700)
|
||||||
|
, Css.textAlign Css.center
|
||||||
|
, case config.border of
|
||||||
|
Nothing ->
|
||||||
|
Css.borderStyle Css.none
|
||||||
|
|
||||||
|
Just color ->
|
||||||
|
Css.batch
|
||||||
|
[ Css.borderColor color
|
||||||
|
, Css.borderStyle Css.solid
|
||||||
|
]
|
||||||
|
, Css.borderBottomStyle Css.solid
|
||||||
|
, Css.borderBottomColor config.shadow
|
||||||
|
, Css.fontStyle Css.normal
|
||||||
|
, Css.hover
|
||||||
|
[ Css.color config.text
|
||||||
|
, Css.backgroundColor config.hover
|
||||||
|
, Css.disabled [ Css.backgroundColor config.background ]
|
||||||
|
]
|
||||||
|
, Css.visited [ Css.color config.text ]
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
sizeStyle : ButtonSize -> ButtonWidth -> Style
|
||||||
|
sizeStyle size width =
|
||||||
|
let
|
||||||
|
config =
|
||||||
|
case size of
|
||||||
|
Small ->
|
||||||
|
{ fontSize = 15
|
||||||
|
, height = 36
|
||||||
|
, imageHeight = 15
|
||||||
|
, shadowHeight = 2
|
||||||
|
, minWidth = 75
|
||||||
|
}
|
||||||
|
|
||||||
|
Medium ->
|
||||||
|
{ fontSize = 17
|
||||||
|
, height = 45
|
||||||
|
, imageHeight = 15
|
||||||
|
, shadowHeight = 3
|
||||||
|
, minWidth = 100
|
||||||
|
}
|
||||||
|
|
||||||
|
Large ->
|
||||||
|
{ fontSize = 20
|
||||||
|
, height = 56
|
||||||
|
, imageHeight = 20
|
||||||
|
, shadowHeight = 4
|
||||||
|
, minWidth = 200
|
||||||
|
}
|
||||||
|
|
||||||
|
sizingAttributes =
|
||||||
|
let
|
||||||
|
verticalPaddingPx =
|
||||||
|
2
|
||||||
|
in
|
||||||
|
[ Css.minHeight (Css.px config.height)
|
||||||
|
, Css.paddingTop (Css.px verticalPaddingPx)
|
||||||
|
, Css.paddingBottom (Css.px verticalPaddingPx)
|
||||||
|
]
|
||||||
|
|
||||||
|
widthAttributes =
|
||||||
|
case width of
|
||||||
|
WidthExact pxWidth ->
|
||||||
|
[ Css.maxWidth (Css.pct 100)
|
||||||
|
, Css.width (Css.px <| toFloat pxWidth)
|
||||||
|
, Css.paddingRight (Css.px 4)
|
||||||
|
, Css.paddingLeft (Css.px 4)
|
||||||
|
]
|
||||||
|
|
||||||
|
WidthUnbounded ->
|
||||||
|
[ Css.paddingLeft (Css.px 16)
|
||||||
|
, Css.paddingRight (Css.px 16)
|
||||||
|
, Css.minWidth (Css.px config.minWidth)
|
||||||
|
]
|
||||||
|
|
||||||
|
lineHeightPx =
|
||||||
|
case size of
|
||||||
|
Small ->
|
||||||
|
15
|
||||||
|
|
||||||
|
Medium ->
|
||||||
|
19
|
||||||
|
|
||||||
|
Large ->
|
||||||
|
22
|
||||||
|
in
|
||||||
|
Css.batch
|
||||||
|
[ Css.fontSize (Css.px config.fontSize)
|
||||||
|
, Css.borderRadius (Css.px 8)
|
||||||
|
, Css.lineHeight (Css.px lineHeightPx)
|
||||||
|
, Css.boxSizing Css.borderBox
|
||||||
|
, Css.borderWidth (Css.px 1)
|
||||||
|
, Css.borderBottomWidth (Css.px config.shadowHeight)
|
||||||
|
, Css.batch sizingAttributes
|
||||||
|
, Css.batch widthAttributes
|
||||||
|
, Css.Foreign.descendants
|
||||||
|
[ Css.Foreign.img
|
||||||
|
[ Css.height (Css.px config.imageHeight)
|
||||||
|
, Css.marginRight (Css.px <| config.imageHeight / 6)
|
||||||
|
, Css.position Css.relative
|
||||||
|
, Css.bottom (Css.px 2)
|
||||||
|
, Css.verticalAlign Css.middle
|
||||||
|
]
|
||||||
|
, Css.Foreign.svg
|
||||||
|
[ Css.height (Css.px config.imageHeight) |> Css.important
|
||||||
|
, Css.width (Css.px config.imageHeight) |> Css.important
|
||||||
|
, Css.marginRight (Css.px <| config.imageHeight / 6)
|
||||||
|
, Css.position Css.relative
|
||||||
|
, Css.bottom (Css.px 2)
|
||||||
|
, Css.verticalAlign Css.middle
|
||||||
|
]
|
||||||
|
, Css.Foreign.svg
|
||||||
|
[ Css.important <| Css.height (Css.px config.imageHeight)
|
||||||
|
, Css.important <| Css.width Css.auto
|
||||||
|
, Css.maxWidth (Css.px (config.imageHeight * 1.25))
|
||||||
|
, Css.paddingRight (Css.px <| config.imageHeight / 6)
|
||||||
|
, Css.position Css.relative
|
||||||
|
, Css.bottom (Css.px 2)
|
||||||
|
, Css.verticalAlign Css.middle
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
styledName : String -> String
|
||||||
|
styledName suffix =
|
||||||
|
"Nri-Ui-Button-V5-" ++ suffix
|
Loading…
Reference in New Issue
Block a user