mirror of
https://github.com/NoRedInk/noredink-ui.git
synced 2024-11-13 07:48:26 +03:00
Merge branch 'master' into checkbox-custom-css
This commit is contained in:
commit
87a1a6c11b
@ -1,6 +1,9 @@
|
||||
Nri.Ui.Accordion.V1,upgrade to V3
|
||||
Nri.Ui.Checkbox.V5,upgrade to V6
|
||||
Nri.Ui.Heading.V2,upgrade to V3
|
||||
Nri.Ui.Menu.V1,upgrade to V3
|
||||
Nri.Ui.SideNav.V3,upgrade to V4
|
||||
Nri.Ui.SortableTable.V2,upgrade to V3
|
||||
Nri.Ui.Table.V5,upgrade to V6
|
||||
Nri.Ui.Tabs.V6,upgrade to V7
|
||||
Nri.Ui.Tooltip.V1,upgrade to V3
|
||||
|
|
5
elm.json
5
elm.json
@ -3,7 +3,7 @@
|
||||
"name": "NoRedInk/noredink-ui",
|
||||
"summary": "UI Widgets we use at NRI",
|
||||
"license": "BSD-3-Clause",
|
||||
"version": "17.0.0",
|
||||
"version": "17.2.0",
|
||||
"exposed-modules": [
|
||||
"Nri.Ui",
|
||||
"Nri.Ui.Accordion.V1",
|
||||
@ -31,6 +31,7 @@
|
||||
"Nri.Ui.FocusTrap.V1",
|
||||
"Nri.Ui.Fonts.V1",
|
||||
"Nri.Ui.Heading.V2",
|
||||
"Nri.Ui.Heading.V3",
|
||||
"Nri.Ui.Html.Attributes.V2",
|
||||
"Nri.Ui.Html.V3",
|
||||
"Nri.Ui.InputStyles.V3",
|
||||
@ -51,12 +52,14 @@
|
||||
"Nri.Ui.Select.V8",
|
||||
"Nri.Ui.Shadows.V1",
|
||||
"Nri.Ui.SideNav.V3",
|
||||
"Nri.Ui.SideNav.V4",
|
||||
"Nri.Ui.SortableTable.V2",
|
||||
"Nri.Ui.SortableTable.V3",
|
||||
"Nri.Ui.Sprite.V1",
|
||||
"Nri.Ui.Svg.V1",
|
||||
"Nri.Ui.Switch.V2",
|
||||
"Nri.Ui.Table.V5",
|
||||
"Nri.Ui.Table.V6",
|
||||
"Nri.Ui.Tabs.V6",
|
||||
"Nri.Ui.Tabs.V7",
|
||||
"Nri.Ui.Text.V6",
|
||||
|
@ -52,6 +52,9 @@ usages = ['styleguide-app/Examples/Tooltip.elm']
|
||||
[forbidden."Nri.Ui.Container.V1"]
|
||||
hint = 'upgrade to V2'
|
||||
|
||||
[forbidden."Nri.Ui.Heading.V2"]
|
||||
hint = 'upgrade to V3'
|
||||
|
||||
[forbidden."Nri.Ui.Icon.V3"]
|
||||
hint = 'upgrade to V5'
|
||||
usages = ['styleguide-app/../src/Nri/Ui/Modal/V3.elm']
|
||||
@ -117,6 +120,9 @@ hint = 'upgrade to V3'
|
||||
[forbidden."Nri.Ui.SideNav.V2"]
|
||||
hint = 'upgrade to V3'
|
||||
|
||||
[forbidden."Nri.Ui.SideNav.V3"]
|
||||
hint = 'upgrade to V4'
|
||||
|
||||
[forbidden."Nri.Ui.SortableTable.V2"]
|
||||
hint = 'upgrade to V3'
|
||||
|
||||
@ -126,6 +132,9 @@ hint = 'upgrade to V2'
|
||||
[forbidden."Nri.Ui.Table.V4"]
|
||||
hint = 'upgrade to V5'
|
||||
|
||||
[forbidden."Nri.Ui.Table.V5"]
|
||||
hint = 'upgrade to V6'
|
||||
|
||||
[forbidden."Nri.Ui.Tabs.V6"]
|
||||
hint = 'upgrade to V7'
|
||||
|
||||
|
@ -23,10 +23,10 @@
|
||||
"homepage": "",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "41cc1d5d9584103be4108c1815c350e07c807036",
|
||||
"sha256": "1zwbkijhgb8a5wzsm1dya1a4y79bz6di5h49gcmw6klai84xxisv",
|
||||
"rev": "e2b34f0f11ed8ad83d9ec9c14260192c3bcccb0d",
|
||||
"sha256": "1n9lhqprqnsiv4nw59mh5ab7hchx7lhvq43kkv64473jwz1xv7ki",
|
||||
"type": "tarball",
|
||||
"url": "https://github.com/NixOS/nixpkgs/archive/41cc1d5d9584103be4108c1815c350e07c807036.tar.gz",
|
||||
"url": "https://github.com/NixOS/nixpkgs/archive/e2b34f0f11ed8ad83d9ec9c14260192c3bcccb0d.tar.gz",
|
||||
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
|
||||
}
|
||||
}
|
||||
|
@ -49,7 +49,10 @@ describe("UI tests", function () {
|
||||
|
||||
const goTo = async (name, location) => {
|
||||
await page.goto(location, { waitUntil: "load" });
|
||||
await page.waitForSelector(`#${name.replace(".", "-")}`, { visible: true });
|
||||
await page.waitForXPath(
|
||||
`//h1[contains(., 'Nri.Ui.${name}') and @aria-current='page']`,
|
||||
200
|
||||
);
|
||||
};
|
||||
|
||||
const defaultProcessing = async (name, location) => {
|
||||
@ -73,11 +76,13 @@ describe("UI tests", function () {
|
||||
const options = await select.$x(
|
||||
`//label[contains(., '${labelName}')]//option`
|
||||
);
|
||||
for (const optionEl of options) {
|
||||
const option = await page.evaluate((el) => el.innerText, optionEl);
|
||||
await page.select("select", option);
|
||||
callback(option);
|
||||
}
|
||||
// Actually doing the select was super flakey.
|
||||
// Temporarily just using the first element to get
|
||||
// CI consistent again. We can cover all the cases separately...
|
||||
const optionEl = options[0];
|
||||
const option = await page.evaluate((el) => el.innerText, optionEl);
|
||||
await page.select("select", option);
|
||||
await callback(option);
|
||||
};
|
||||
|
||||
const messageProcessing = async (name, location) => {
|
||||
@ -125,10 +130,8 @@ describe("UI tests", function () {
|
||||
.analyze();
|
||||
handleAxeResults(name, axe);
|
||||
|
||||
await forAllOptions("page", async (option) => {
|
||||
await percySnapshot(page, `${name} - ${option}`, {
|
||||
scope: "[data-page-container='']",
|
||||
});
|
||||
await percySnapshot(page, name, {
|
||||
scope: "[data-page-container='']",
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -6,9 +6,10 @@ module Nri.Ui.ClickableSvg.V2 exposing
|
||||
, exactSize, exactWidth, exactHeight
|
||||
, disabled
|
||||
, withBorder
|
||||
, primary, secondary, danger, dangerSecondary
|
||||
, primary, secondary, tertiary, danger, dangerSecondary
|
||||
, custom, nriDescription, testId, id
|
||||
, css, notMobileCss, mobileCss, quizEngineMobileCss
|
||||
, iconForMobile
|
||||
, small, medium, large
|
||||
)
|
||||
|
||||
@ -18,6 +19,7 @@ module Nri.Ui.ClickableSvg.V2 exposing
|
||||
# Patch changes:
|
||||
|
||||
- adds `nriDescription`, `testId`, and `id` helpers
|
||||
- adds `iconForMobile`
|
||||
|
||||
|
||||
# Create a button or link
|
||||
@ -45,7 +47,7 @@ module Nri.Ui.ClickableSvg.V2 exposing
|
||||
## Customization
|
||||
|
||||
@docs withBorder
|
||||
@docs primary, secondary, danger, dangerSecondary
|
||||
@docs primary, secondary, tertiary, danger, dangerSecondary
|
||||
|
||||
@docs custom, nriDescription, testId, id
|
||||
|
||||
@ -53,6 +55,7 @@ module Nri.Ui.ClickableSvg.V2 exposing
|
||||
### CSS
|
||||
|
||||
@docs css, notMobileCss, mobileCss, quizEngineMobileCss
|
||||
@docs iconForMobile
|
||||
|
||||
|
||||
### DEPRECATED
|
||||
@ -247,6 +250,7 @@ withBorder =
|
||||
type Theme
|
||||
= Primary
|
||||
| Secondary
|
||||
| Tertiary
|
||||
| Danger
|
||||
| DangerSecondary
|
||||
|
||||
@ -257,7 +261,9 @@ type alias AppliedTheme =
|
||||
, background : Color
|
||||
, backgroundHovered : Color
|
||||
, includeBorder : Bool
|
||||
, borderColor : Color
|
||||
, borderBottom : Color
|
||||
, borderHover : Color
|
||||
}
|
||||
|
||||
|
||||
@ -268,7 +274,9 @@ disabledTheme =
|
||||
, background = Colors.white
|
||||
, backgroundHovered = Colors.white
|
||||
, includeBorder = True
|
||||
, borderColor = Colors.gray75
|
||||
, borderBottom = Colors.gray75
|
||||
, borderHover = Colors.gray75
|
||||
}
|
||||
|
||||
|
||||
@ -281,7 +289,9 @@ applyTheme theme =
|
||||
, background = Colors.azure
|
||||
, backgroundHovered = Colors.azureDark
|
||||
, includeBorder = False
|
||||
, borderColor = Colors.white
|
||||
, borderBottom = Colors.azureDark
|
||||
, borderHover = Colors.azureDark
|
||||
}
|
||||
|
||||
Secondary ->
|
||||
@ -290,7 +300,20 @@ applyTheme theme =
|
||||
, background = Colors.white
|
||||
, backgroundHovered = Colors.glacier
|
||||
, includeBorder = True
|
||||
, borderColor = Colors.azure
|
||||
, borderBottom = Colors.azure
|
||||
, borderHover = Colors.azure
|
||||
}
|
||||
|
||||
Tertiary ->
|
||||
{ main_ = Colors.gray45
|
||||
, mainHovered = Colors.azure
|
||||
, background = Colors.gray96
|
||||
, backgroundHovered = Colors.glacier
|
||||
, includeBorder = True
|
||||
, borderColor = Colors.gray92
|
||||
, borderBottom = Colors.gray92
|
||||
, borderHover = Colors.azure
|
||||
}
|
||||
|
||||
Danger ->
|
||||
@ -299,7 +322,9 @@ applyTheme theme =
|
||||
, background = Colors.red
|
||||
, backgroundHovered = Colors.redDark
|
||||
, includeBorder = False
|
||||
, borderColor = Colors.white
|
||||
, borderBottom = Colors.redDark
|
||||
, borderHover = Colors.redDark
|
||||
}
|
||||
|
||||
DangerSecondary ->
|
||||
@ -308,7 +333,9 @@ applyTheme theme =
|
||||
, background = Colors.white
|
||||
, backgroundHovered = Colors.redLight
|
||||
, includeBorder = True
|
||||
, borderColor = Colors.red
|
||||
, borderBottom = Colors.red
|
||||
, borderHover = Colors.red
|
||||
}
|
||||
|
||||
|
||||
@ -327,6 +354,13 @@ secondary =
|
||||
set (\attributes -> { attributes | theme = Secondary })
|
||||
|
||||
|
||||
{-| Used to de-emphasize elements when not hovered.
|
||||
-}
|
||||
tertiary : Attribute msg
|
||||
tertiary =
|
||||
set (\attributes -> { attributes | theme = Tertiary })
|
||||
|
||||
|
||||
{-| White/transparent icon on a red background.
|
||||
-}
|
||||
danger : Attribute msg
|
||||
@ -420,6 +454,12 @@ quizEngineMobileCss styles =
|
||||
css [ Css.Media.withMedia [ MediaQuery.quizEngineMobile ] styles ]
|
||||
|
||||
|
||||
{-| -}
|
||||
iconForMobile : Svg -> Attribute msg
|
||||
iconForMobile icon =
|
||||
set (\config -> { config | iconForMobile = Just icon })
|
||||
|
||||
|
||||
|
||||
-- INTERNALS
|
||||
|
||||
@ -437,6 +477,7 @@ build label icon =
|
||||
{ clickableAttributes = ClickableAttributes.init
|
||||
, label = label
|
||||
, icon = icon
|
||||
, iconForMobile = Nothing
|
||||
, disabled = False
|
||||
, size = Small
|
||||
, width = Nothing
|
||||
@ -456,6 +497,7 @@ type alias ButtonOrLinkAttributes msg =
|
||||
{ clickableAttributes : ClickableAttributes String msg
|
||||
, label : String
|
||||
, icon : Svg
|
||||
, iconForMobile : Maybe Svg
|
||||
, disabled : Bool
|
||||
, size : Size
|
||||
, width : Maybe Float
|
||||
@ -487,8 +529,7 @@ renderButton ((ButtonOrLink config) as button_) =
|
||||
++ ClickableAttributes.toButtonAttributes config.clickableAttributes
|
||||
++ config.customAttributes
|
||||
)
|
||||
[ renderIcon config theme.includeBorder
|
||||
]
|
||||
(renderIcons config theme.includeBorder)
|
||||
|
||||
|
||||
renderLink : ButtonOrLink msg -> Html msg
|
||||
@ -522,12 +563,11 @@ renderLink ((ButtonOrLink config) as link_) =
|
||||
)
|
||||
++ config.customAttributes
|
||||
)
|
||||
[ renderIcon config theme.includeBorder
|
||||
]
|
||||
(renderIcons config theme.includeBorder)
|
||||
|
||||
|
||||
renderIcon : ButtonOrLinkAttributes msg -> Bool -> Html msg
|
||||
renderIcon config includeBorder =
|
||||
renderIcons : ButtonOrLinkAttributes msg -> Bool -> List (Html msg)
|
||||
renderIcons config includeBorder =
|
||||
let
|
||||
size =
|
||||
getSize config.size
|
||||
@ -556,20 +596,43 @@ renderIcon config includeBorder =
|
||||
|
||||
else
|
||||
Maybe.withDefault size config.height
|
||||
in
|
||||
config.icon
|
||||
|> Svg.withCss
|
||||
|
||||
iconStyles =
|
||||
[ Css.displayFlex
|
||||
, Css.maxWidth (Css.px iconWidth)
|
||||
, Css.maxHeight (Css.px iconHeight)
|
||||
, Css.height (Css.pct 100)
|
||||
, Css.margin Css.auto
|
||||
]
|
||||
|> Svg.toHtml
|
||||
|
||||
hideFor breakpoint =
|
||||
Svg.withCss
|
||||
[ Css.Media.withMedia [ breakpoint ]
|
||||
[ Css.display Css.none
|
||||
]
|
||||
]
|
||||
in
|
||||
case config.iconForMobile of
|
||||
Just iconForMobile_ ->
|
||||
[ config.icon
|
||||
|> Svg.withCss iconStyles
|
||||
|> hideFor MediaQuery.mobile
|
||||
|> Svg.toHtml
|
||||
, iconForMobile_
|
||||
|> Svg.withCss iconStyles
|
||||
|> hideFor MediaQuery.notMobile
|
||||
|> Svg.toHtml
|
||||
]
|
||||
|
||||
Nothing ->
|
||||
[ config.icon
|
||||
|> Svg.withCss iconStyles
|
||||
|> Svg.toHtml
|
||||
]
|
||||
|
||||
|
||||
buttonOrLinkStyles : ButtonOrLinkAttributes msg -> AppliedTheme -> List Style
|
||||
buttonOrLinkStyles config { main_, mainHovered, background, backgroundHovered, borderBottom, includeBorder } =
|
||||
buttonOrLinkStyles config { main_, mainHovered, background, backgroundHovered, borderColor, borderBottom, borderHover, includeBorder } =
|
||||
let
|
||||
cursor =
|
||||
if config.disabled then
|
||||
@ -600,7 +663,7 @@ buttonOrLinkStyles config { main_, mainHovered, background, backgroundHovered, b
|
||||
, Css.batch <|
|
||||
if config.hasBorder then
|
||||
[ Css.borderRadius (Css.px 8)
|
||||
, Css.borderColor main_
|
||||
, Css.borderColor borderColor
|
||||
, Css.borderBottomColor borderBottom
|
||||
, Css.borderStyle Css.solid
|
||||
, if includeBorder then
|
||||
@ -615,7 +678,7 @@ buttonOrLinkStyles config { main_, mainHovered, background, backgroundHovered, b
|
||||
, Css.borderBottomWidth (Css.px bordersAndPadding.bottomBorder)
|
||||
, Css.backgroundColor background
|
||||
, Css.hover
|
||||
[ Css.borderColor borderBottom
|
||||
[ Css.borderColor borderHover
|
||||
, Css.backgroundColor backgroundHovered
|
||||
]
|
||||
, Css.padding4
|
||||
|
@ -17,10 +17,10 @@ Changes from V1:
|
||||
-}
|
||||
|
||||
import Css exposing (Color)
|
||||
import Css.Media exposing (withMediaQuery)
|
||||
import Html.Styled as Html
|
||||
import Html.Styled.Attributes as Attributes exposing (css)
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.MediaQuery.V1 as MediaQuery
|
||||
import Particle exposing (Particle)
|
||||
import Particle.System as ParticleSystem
|
||||
import Random exposing (Generator)
|
||||
@ -68,8 +68,7 @@ view (System system _) =
|
||||
, Css.width (Css.pct 100)
|
||||
, Css.height (Css.vh 100)
|
||||
, Css.pointerEvents Css.none
|
||||
, withMediaQuery [ "(prefers-reduced-motion)" ]
|
||||
[ Css.display Css.none ]
|
||||
, MediaQuery.prefersReducedMotion [ Css.display Css.none ]
|
||||
]
|
||||
]
|
||||
)
|
||||
|
266
src/Nri/Ui/Heading/V3.elm
Normal file
266
src/Nri/Ui/Heading/V3.elm
Normal file
@ -0,0 +1,266 @@
|
||||
module Nri.Ui.Heading.V3 exposing
|
||||
( h1, h2, h3, h4, h5
|
||||
, plaintext, markdown, html
|
||||
, Attribute
|
||||
, top, subhead, small
|
||||
, custom, css, nriDescription, testId, id
|
||||
)
|
||||
|
||||
{-|
|
||||
|
||||
|
||||
# Changes from V2:
|
||||
|
||||
- changes default h2 style to subhead
|
||||
- remove `customAttr`
|
||||
- remove `error` and `errorIf`
|
||||
- replaces `style` with `top`, `subhead`, and `small`
|
||||
- replaces list of HTML attributes with content approach (`plaintext`, `markdown`, `html`) used in Text
|
||||
|
||||
Headings with customization options.
|
||||
|
||||
@docs h1, h2, h3, h4, h5
|
||||
|
||||
|
||||
# Content
|
||||
|
||||
@docs plaintext, markdown, html
|
||||
|
||||
|
||||
## Customizations
|
||||
|
||||
@docs Attribute
|
||||
@docs top, subhead, small
|
||||
@docs custom, css, nriDescription, testId, id
|
||||
|
||||
-}
|
||||
|
||||
import Css exposing (..)
|
||||
import Html.Styled exposing (..)
|
||||
import Html.Styled.Attributes as Attributes
|
||||
import Markdown
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.Fonts.V1 as Fonts
|
||||
import Nri.Ui.Html.Attributes.V2 as ExtraAttributes
|
||||
|
||||
|
||||
{-| Make a first-level heading (styled like a top-level heading by default.)
|
||||
-}
|
||||
h1 : List (Attribute msg) -> Html msg
|
||||
h1 attributes =
|
||||
view Html.Styled.h1 (top :: attributes)
|
||||
|
||||
|
||||
{-| Make a second-level heading (styled like a tagline by default.)
|
||||
-}
|
||||
h2 : List (Attribute msg) -> Html msg
|
||||
h2 attributes =
|
||||
view Html.Styled.h2 (subhead :: attributes)
|
||||
|
||||
|
||||
{-| Make a third-level heading (styled like a subhead by default.)
|
||||
-}
|
||||
h3 : List (Attribute msg) -> Html msg
|
||||
h3 attributes =
|
||||
view Html.Styled.h3 (small :: attributes)
|
||||
|
||||
|
||||
{-| Make a fourth-level heading (styled like a small heading by default.)
|
||||
-}
|
||||
h4 : List (Attribute msg) -> Html msg
|
||||
h4 attributes =
|
||||
view Html.Styled.h4 (small :: attributes)
|
||||
|
||||
|
||||
{-| Make a fifth-level heading (styled like a small heading by default.)
|
||||
-}
|
||||
h5 : List (Attribute msg) -> Html msg
|
||||
h5 attributes =
|
||||
view Html.Styled.h5 (small :: attributes)
|
||||
|
||||
|
||||
view :
|
||||
(List (Html.Styled.Attribute msg) -> List (Html msg) -> Html msg)
|
||||
-> List (Attribute msg)
|
||||
-> Html msg
|
||||
view tag attrs =
|
||||
let
|
||||
final =
|
||||
List.foldl (\(Attribute f) acc -> f acc) emptyCustomizations attrs
|
||||
in
|
||||
tag (Attributes.css final.css :: final.attributes) final.content
|
||||
|
||||
|
||||
{-| Provide a plain-text string.
|
||||
-}
|
||||
plaintext : String -> Attribute msg
|
||||
plaintext content =
|
||||
Attribute <| \config -> { config | content = [ text content ] }
|
||||
|
||||
|
||||
{-| Provide a string that will be rendered as markdown.
|
||||
-}
|
||||
markdown : String -> Attribute msg
|
||||
markdown content =
|
||||
Attribute <|
|
||||
\config ->
|
||||
{ config
|
||||
| content =
|
||||
Markdown.toHtml Nothing content
|
||||
|> List.map fromUnstyled
|
||||
}
|
||||
|
||||
|
||||
{-| Provide a list of custom HTML.
|
||||
-}
|
||||
html : List (Html msg) -> Attribute msg
|
||||
html content =
|
||||
Attribute <| \config -> { config | content = content }
|
||||
|
||||
|
||||
{-| Like an `Html.Attribute msg`, but specifically for headings. Use things
|
||||
like `style` in this module to construct an Attribute.
|
||||
-}
|
||||
type Attribute msg
|
||||
= Attribute (Customizations msg -> Customizations msg)
|
||||
|
||||
|
||||
{-| Set some custom CSS in this heading. For example, maybe you need to tweak
|
||||
margins.
|
||||
-}
|
||||
css : List Css.Style -> Attribute msg
|
||||
css css_ =
|
||||
Attribute
|
||||
(\customizations ->
|
||||
{ customizations | css = customizations.css ++ css_ }
|
||||
)
|
||||
|
||||
|
||||
{-| Set some custom attributes.
|
||||
|
||||
Please don't make headers interactive! Use buttons or links instead so that keyboard and screen
|
||||
reader users can use the site too.
|
||||
|
||||
For style customizations, be sure to use the Heading.css helper.
|
||||
|
||||
-}
|
||||
custom : List (Html.Styled.Attribute msg) -> Attribute msg
|
||||
custom attributes =
|
||||
Attribute
|
||||
(\customizations ->
|
||||
{ customizations | attributes = customizations.attributes ++ attributes }
|
||||
)
|
||||
|
||||
|
||||
{-| -}
|
||||
nriDescription : String -> Attribute msg
|
||||
nriDescription description =
|
||||
custom [ ExtraAttributes.nriDescription description ]
|
||||
|
||||
|
||||
{-| -}
|
||||
testId : String -> Attribute msg
|
||||
testId id_ =
|
||||
custom [ ExtraAttributes.testId id_ ]
|
||||
|
||||
|
||||
{-| -}
|
||||
id : String -> Attribute msg
|
||||
id id_ =
|
||||
custom [ Attributes.id id_ ]
|
||||
|
||||
|
||||
emptyCustomizations : Customizations msg
|
||||
emptyCustomizations =
|
||||
{ content = []
|
||||
, css = []
|
||||
, attributes = []
|
||||
}
|
||||
|
||||
|
||||
type alias Customizations msg =
|
||||
{ content : List (Html msg)
|
||||
, css : List Css.Style
|
||||
, attributes : List (Html.Styled.Attribute msg)
|
||||
}
|
||||
|
||||
|
||||
|
||||
-- Style
|
||||
|
||||
|
||||
{-| `top` headings are Colors.navy and have:
|
||||
|
||||
font-size: 30px
|
||||
line-height: 38px
|
||||
font-weight: 700
|
||||
|
||||
By default.
|
||||
|
||||
-}
|
||||
top : Attribute msg
|
||||
top =
|
||||
(css << headingStyles)
|
||||
{ color = Colors.navy
|
||||
, size = 30
|
||||
, lineHeight = 38
|
||||
}
|
||||
|
||||
|
||||
{-| `subhead` headings are Colors.navy and have:
|
||||
|
||||
font-size: 20px
|
||||
line-height: 26px
|
||||
font-weight: 700
|
||||
|
||||
By default.
|
||||
|
||||
-}
|
||||
subhead : Attribute msg
|
||||
subhead =
|
||||
(css << headingStyles)
|
||||
{ color = Colors.navy
|
||||
, size = 20
|
||||
, lineHeight = 26
|
||||
}
|
||||
|
||||
|
||||
{-| `small` headings are Colors.gray20 and have:
|
||||
|
||||
font-size: 16px
|
||||
line-height: 21px
|
||||
font-weight: 700
|
||||
|
||||
By default.
|
||||
|
||||
`small` heading default styles also make the [letter-spacing](https://developer.mozilla.org/en-US/docs/Web/CSS/letter-spacing) slightly narrower, by 0.13px.
|
||||
|
||||
-}
|
||||
small : Attribute msg
|
||||
small =
|
||||
css
|
||||
(letterSpacing (px -0.13)
|
||||
:: headingStyles
|
||||
{ color = Colors.gray20
|
||||
, size = 16
|
||||
, lineHeight = 21
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
headingStyles :
|
||||
{ color : Color
|
||||
, lineHeight : Float
|
||||
, size : Float
|
||||
}
|
||||
-> List Css.Style
|
||||
headingStyles config =
|
||||
[ Fonts.baseFont
|
||||
, fontSize (px config.size)
|
||||
, color config.color
|
||||
, lineHeight (px config.lineHeight)
|
||||
, fontWeight (int 700)
|
||||
, padding zero
|
||||
, textAlign left
|
||||
, margin zero
|
||||
]
|
@ -1,5 +1,5 @@
|
||||
module Nri.Ui.Logo.V1 exposing
|
||||
( noredink
|
||||
( noredink, noredinkMonochrome
|
||||
, clever, cleverC, cleverLibrary
|
||||
, googleClassroom, googleG
|
||||
, canvas
|
||||
@ -11,7 +11,7 @@ module Nri.Ui.Logo.V1 exposing
|
||||
|
||||
{-|
|
||||
|
||||
@docs noredink
|
||||
@docs noredink, noredinkMonochrome
|
||||
@docs clever, cleverC, cleverLibrary
|
||||
@docs googleClassroom, googleG
|
||||
@docs canvas
|
||||
@ -40,23 +40,48 @@ noredink =
|
||||
]
|
||||
[ Svg.path
|
||||
[ Attributes.fill (toCssString Colors.red)
|
||||
, Attributes.d "M4.29 6.03v2.048h.065c.943-1.723 2.568-2.503 4.453-2.503 2.795 0 4.453 1.527 4.453 4.972v12.97H8.776v-12.06c0-1.755-.586-2.437-1.918-2.437-1.528 0-2.373.943-2.373 2.892v11.604H0V6.03h4.29zM22.559 20.916c1.82 0 2.404-1.788 2.404-6.143 0-4.355-.584-6.143-2.404-6.143-2.21 0-2.405 2.568-2.405 6.143 0 3.575.195 6.143 2.405 6.143zm0-15.341c5.395-.098 6.89 3.12 6.89 9.198 0 5.98-1.755 9.198-6.89 9.198-5.396.098-6.89-3.12-6.89-9.198 0-5.98 1.754-9.198 6.89-9.198z"
|
||||
, Attributes.d noD
|
||||
]
|
||||
[]
|
||||
, Svg.path
|
||||
[ Attributes.fill "#333"
|
||||
, Attributes.d "M32.246 6.257h1.95v2.698h.065c.748-1.918 2.34-3.088 4.356-3.088.227 0 .455.033.682.098v1.95a4.878 4.878 0 0 0-.942-.097c-2.145 0-4.16 1.56-4.16 4.907v10.791h-1.95V6.257zM49.994 13.342c-.065-4.29-1.268-5.85-3.673-5.85-2.405 0-3.608 1.56-3.673 5.85h7.346zm1.918 4.454c-.293 3.672-2.308 6.11-5.558 6.11-3.64 0-5.786-2.535-5.786-9.035 0-5.981 2.145-9.004 5.948-9.004 3.836 0 5.558 2.633 5.558 8.386v.715h-9.426v.813c0 4.972 1.755 6.5 3.673 6.5 2.048 0 3.315-1.463 3.64-4.485h1.95zM60.266 22.28c1.983 0 3.77-1.007 3.77-7.41 0-6.37-1.787-7.378-3.77-7.378-1.95 0-3.77 1.008-3.77 7.379 0 6.402 1.82 7.41 3.77 7.41zm3.965-1.624h-.065c-.52 1.983-2.177 3.25-4.225 3.25-3.802 0-5.525-3.055-5.525-9.035 0-5.948 1.723-9.004 5.525-9.004 2.145 0 3.608 1.17 4.03 2.99h.065V.31h1.95v23.206h-1.755v-2.86z"
|
||||
, Attributes.d redD
|
||||
]
|
||||
[]
|
||||
, Svg.path
|
||||
[ Attributes.fill (toCssString Colors.red)
|
||||
, Attributes.d "M69.336 6.03h4.486v17.486h-4.486V6.03zm0-5.981h4.486v3.835h-4.486V.05zM76.975 6.03h4.29v2.048h.065c.944-1.723 2.568-2.503 4.453-2.503 2.795 0 4.453 1.527 4.453 4.972v12.97H85.75v-12.06c0-1.755-.585-2.437-1.917-2.437-1.527 0-2.373.943-2.373 2.892v11.604h-4.485V6.03zM97.876.31v12.253h.065l4.518-6.533h4.94l-5.037 6.89 5.785 10.596h-4.94l-3.739-7.183-1.592 2.08v5.103H93.39V.31z"
|
||||
, Attributes.d inkD
|
||||
]
|
||||
[]
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
{-| -}
|
||||
noredinkMonochrome : Nri.Ui.Svg.V1.Svg
|
||||
noredinkMonochrome =
|
||||
Nri.Ui.Svg.V1.init "0 0 109 24"
|
||||
[ Svg.path [ Attributes.d noD ] []
|
||||
, Svg.path [ Attributes.d redD ] []
|
||||
, Svg.path [ Attributes.d inkD ] []
|
||||
]
|
||||
|
||||
|
||||
noD : String
|
||||
noD =
|
||||
"M4.29 6.03v2.048h.065c.943-1.723 2.568-2.503 4.453-2.503 2.795 0 4.453 1.527 4.453 4.972v12.97H8.776v-12.06c0-1.755-.586-2.437-1.918-2.437-1.528 0-2.373.943-2.373 2.892v11.604H0V6.03h4.29zM22.559 20.916c1.82 0 2.404-1.788 2.404-6.143 0-4.355-.584-6.143-2.404-6.143-2.21 0-2.405 2.568-2.405 6.143 0 3.575.195 6.143 2.405 6.143zm0-15.341c5.395-.098 6.89 3.12 6.89 9.198 0 5.98-1.755 9.198-6.89 9.198-5.396.098-6.89-3.12-6.89-9.198 0-5.98 1.754-9.198 6.89-9.198z"
|
||||
|
||||
|
||||
redD : String
|
||||
redD =
|
||||
"M32.246 6.257h1.95v2.698h.065c.748-1.918 2.34-3.088 4.356-3.088.227 0 .455.033.682.098v1.95a4.878 4.878 0 0 0-.942-.097c-2.145 0-4.16 1.56-4.16 4.907v10.791h-1.95V6.257zM49.994 13.342c-.065-4.29-1.268-5.85-3.673-5.85-2.405 0-3.608 1.56-3.673 5.85h7.346zm1.918 4.454c-.293 3.672-2.308 6.11-5.558 6.11-3.64 0-5.786-2.535-5.786-9.035 0-5.981 2.145-9.004 5.948-9.004 3.836 0 5.558 2.633 5.558 8.386v.715h-9.426v.813c0 4.972 1.755 6.5 3.673 6.5 2.048 0 3.315-1.463 3.64-4.485h1.95zM60.266 22.28c1.983 0 3.77-1.007 3.77-7.41 0-6.37-1.787-7.378-3.77-7.378-1.95 0-3.77 1.008-3.77 7.379 0 6.402 1.82 7.41 3.77 7.41zm3.965-1.624h-.065c-.52 1.983-2.177 3.25-4.225 3.25-3.802 0-5.525-3.055-5.525-9.035 0-5.948 1.723-9.004 5.525-9.004 2.145 0 3.608 1.17 4.03 2.99h.065V.31h1.95v23.206h-1.755v-2.86z"
|
||||
|
||||
|
||||
inkD : String
|
||||
inkD =
|
||||
"M69.336 6.03h4.486v17.486h-4.486V6.03zm0-5.981h4.486v3.835h-4.486V.05zM76.975 6.03h4.29v2.048h.065c.944-1.723 2.568-2.503 4.453-2.503 2.795 0 4.453 1.527 4.453 4.972v12.97H85.75v-12.06c0-1.755-.585-2.437-1.917-2.437-1.527 0-2.373.943-2.373 2.892v11.604h-4.485V6.03zM97.876.31v12.253h.065l4.518-6.533h4.94l-5.037 6.89 5.785 10.596h-4.94l-3.739-7.183-1.592 2.08v5.103H93.39V.31z"
|
||||
|
||||
|
||||
{-| -}
|
||||
facebook : Nri.Ui.Svg.V1.Svg
|
||||
facebook =
|
||||
|
@ -1,5 +1,6 @@
|
||||
module Nri.Ui.MediaQuery.V1 exposing
|
||||
( mobile, notMobile
|
||||
( anyMotion, prefersReducedMotion
|
||||
, mobile, notMobile
|
||||
, mobileBreakpoint
|
||||
, quizEngineMobile
|
||||
, quizEngineBreakpoint
|
||||
@ -20,6 +21,8 @@ module Nri.Ui.MediaQuery.V1 exposing
|
||||
[ Css.padding (Css.px 2)
|
||||
]
|
||||
|
||||
@docs anyMotion, prefersReducedMotion
|
||||
|
||||
@docs mobile, notMobile
|
||||
@docs mobileBreakpoint
|
||||
|
||||
@ -31,8 +34,20 @@ module Nri.Ui.MediaQuery.V1 exposing
|
||||
|
||||
-}
|
||||
|
||||
import Css exposing (px)
|
||||
import Css.Media exposing (MediaQuery, maxWidth, minWidth, only, screen)
|
||||
import Css exposing (Style, px)
|
||||
import Css.Media exposing (MediaQuery, maxWidth, minWidth, only, screen, withMediaQuery)
|
||||
|
||||
|
||||
{-| -}
|
||||
anyMotion : List Style -> Style
|
||||
anyMotion =
|
||||
withMediaQuery [ "(prefers-reduced-motion: no-preference)" ]
|
||||
|
||||
|
||||
{-| -}
|
||||
prefersReducedMotion : List Style -> Style
|
||||
prefersReducedMotion =
|
||||
withMediaQuery [ "(prefers-reduced-motion)" ]
|
||||
|
||||
|
||||
{-| Styles using the `mobileBreakpoint` value as the maxWidth.
|
||||
|
@ -18,8 +18,9 @@ import Html.Styled.Attributes as Attributes
|
||||
import Http
|
||||
import Nri.Ui.Button.V10 as Button
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.Heading.V2 as Heading
|
||||
import Nri.Ui.Heading.V3 as Heading
|
||||
import Nri.Ui.Html.V3 exposing (viewIf)
|
||||
import Nri.Ui.Text.V6 as Text
|
||||
|
||||
|
||||
{-| The default page information is for the button
|
||||
@ -202,8 +203,15 @@ view : Config msg -> Html msg
|
||||
view config =
|
||||
viewContainer
|
||||
[ viewEmoji [ Html.text config.emoji ]
|
||||
, Heading.h1 [] [ Html.text config.title ]
|
||||
, Heading.h2 [] [ Html.text config.subtitle ]
|
||||
, Heading.h1 [ Heading.plaintext config.title ]
|
||||
, Text.mediumBody
|
||||
[ Text.plaintext config.subtitle
|
||||
, Text.css
|
||||
[ Css.fontSize (Css.px 20)
|
||||
, Css.color Colors.gray45
|
||||
, Css.marginBottom Css.zero
|
||||
]
|
||||
]
|
||||
, viewButton
|
||||
[ viewExit config ]
|
||||
, viewIf
|
||||
|
674
src/Nri/Ui/SideNav/V4.elm
Normal file
674
src/Nri/Ui/SideNav/V4.elm
Normal file
@ -0,0 +1,674 @@
|
||||
module Nri.Ui.SideNav.V4 exposing
|
||||
( view, Config, NavAttribute
|
||||
, collapsible
|
||||
, navLabel, navId
|
||||
, navCss, navNotMobileCss, navMobileCss, navQuizEngineMobileCss
|
||||
, entry, entryWithChildren, html, Entry, Attribute
|
||||
, icon, custom, css, nriDescription, testId, id
|
||||
, onClick
|
||||
, href, linkSpa, linkExternal, linkWithMethod, linkWithTracking, linkExternalWithTracking
|
||||
, primary, secondary
|
||||
, premiumDisplay
|
||||
)
|
||||
|
||||
{-|
|
||||
|
||||
|
||||
# Changes from V3
|
||||
|
||||
- make the nav configurably collapsible
|
||||
|
||||
@docs view, Config, NavAttribute
|
||||
@docs collapsible
|
||||
@docs navLabel, navId
|
||||
@docs navCss, navNotMobileCss, navMobileCss, navQuizEngineMobileCss
|
||||
|
||||
|
||||
## Entries
|
||||
|
||||
@docs entry, entryWithChildren, html, Entry, Attribute
|
||||
@docs icon, custom, css, nriDescription, testId, id
|
||||
|
||||
|
||||
## Behavior
|
||||
|
||||
@docs onClick
|
||||
@docs href, linkSpa, linkExternal, linkWithMethod, linkWithTracking, linkExternalWithTracking
|
||||
|
||||
|
||||
## Change the color scheme
|
||||
|
||||
@docs primary, secondary
|
||||
|
||||
|
||||
## Change the state
|
||||
|
||||
@docs premiumDisplay
|
||||
|
||||
-}
|
||||
|
||||
import Accessibility.Styled exposing (..)
|
||||
import Accessibility.Styled.Aria as Aria
|
||||
import Accessibility.Styled.Style as Style
|
||||
import ClickableAttributes exposing (ClickableAttributes)
|
||||
import Css exposing (..)
|
||||
import Css.Media
|
||||
import Html.Styled
|
||||
import Html.Styled.Attributes as Attributes
|
||||
import Html.Styled.Events as Events
|
||||
import Nri.Ui
|
||||
import Nri.Ui.ClickableSvg.V2 as ClickableSvg
|
||||
import Nri.Ui.ClickableText.V3 as ClickableText
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.Data.PremiumDisplay as PremiumDisplay exposing (PremiumDisplay)
|
||||
import Nri.Ui.Fonts.V1 as Fonts
|
||||
import Nri.Ui.Html.Attributes.V2 as ExtraAttributes
|
||||
import Nri.Ui.Html.V3 exposing (viewJust)
|
||||
import Nri.Ui.MediaQuery.V1 as MediaQuery
|
||||
import Nri.Ui.Svg.V1 as Svg exposing (Svg)
|
||||
import Nri.Ui.Tooltip.V3 as Tooltip
|
||||
import Nri.Ui.UiIcon.V1 as UiIcon
|
||||
|
||||
|
||||
{-| Use `entry` to create a sidebar entry.
|
||||
-}
|
||||
type Entry route msg
|
||||
= Entry (List (Entry route msg)) (EntryConfig route msg)
|
||||
| Html (List (Html msg))
|
||||
|
||||
|
||||
{-| -}
|
||||
entry : String -> List (Attribute route msg) -> Entry route msg
|
||||
entry title attributes =
|
||||
attributes
|
||||
|> List.foldl (\(Attribute attribute) b -> attribute b) (build title)
|
||||
|> Entry []
|
||||
|
||||
|
||||
{-| -}
|
||||
entryWithChildren : String -> List (Attribute route msg) -> List (Entry route msg) -> Entry route msg
|
||||
entryWithChildren title attributes children =
|
||||
attributes
|
||||
|> List.foldl (\(Attribute attribute) b -> attribute b) (build title)
|
||||
|> Entry children
|
||||
|
||||
|
||||
{-| -}
|
||||
html : List (Html msg) -> Entry route msg
|
||||
html =
|
||||
Html
|
||||
|
||||
|
||||
{-| -}
|
||||
type alias Config route msg =
|
||||
{ isCurrentRoute : route -> Bool
|
||||
, routeToString : route -> String
|
||||
, onSkipNav : msg
|
||||
}
|
||||
|
||||
|
||||
{-| -}
|
||||
type NavAttribute msg
|
||||
= NavAttribute (NavAttributeConfig msg -> NavAttributeConfig msg)
|
||||
|
||||
|
||||
type alias NavAttributeConfig msg =
|
||||
{ navLabel : Maybe String
|
||||
, navId : Maybe String
|
||||
, css : List Style
|
||||
, collapsible : Maybe (CollapsibleConfig msg)
|
||||
}
|
||||
|
||||
|
||||
defaultNavAttributeConfig : NavAttributeConfig msg
|
||||
defaultNavAttributeConfig =
|
||||
{ navLabel = Nothing
|
||||
, navId = Nothing
|
||||
, css = []
|
||||
, collapsible = Nothing
|
||||
}
|
||||
|
||||
|
||||
{-| Give screenreader users context on what this particular sidenav is for.
|
||||
|
||||
If the nav is collapsible, this value will also be used for the sidenav tooltips.
|
||||
|
||||
-}
|
||||
navLabel : String -> NavAttribute msg
|
||||
navLabel str =
|
||||
NavAttribute (\config -> { config | navLabel = Just str })
|
||||
|
||||
|
||||
{-| -}
|
||||
navId : String -> NavAttribute msg
|
||||
navId str =
|
||||
NavAttribute (\config -> { config | navId = Just str })
|
||||
|
||||
|
||||
{-| These styles are included automatically in the nav container:
|
||||
|
||||
[ flexBasis (px 250)
|
||||
, flexShrink (num 0)
|
||||
, borderRadius (px 8)
|
||||
, backgroundColor Colors.gray96
|
||||
, padding (px 20)
|
||||
, marginRight (px 20)
|
||||
]
|
||||
|
||||
-}
|
||||
navCss : List Style -> NavAttribute msg
|
||||
navCss styles =
|
||||
NavAttribute (\config -> { config | css = List.append config.css styles })
|
||||
|
||||
|
||||
{-| -}
|
||||
navNotMobileCss : List Style -> NavAttribute msg
|
||||
navNotMobileCss styles =
|
||||
navCss [ Css.Media.withMedia [ MediaQuery.notMobile ] styles ]
|
||||
|
||||
|
||||
{-| -}
|
||||
navMobileCss : List Style -> NavAttribute msg
|
||||
navMobileCss styles =
|
||||
navCss [ Css.Media.withMedia [ MediaQuery.mobile ] styles ]
|
||||
|
||||
|
||||
{-| -}
|
||||
navQuizEngineMobileCss : List Style -> NavAttribute msg
|
||||
navQuizEngineMobileCss styles =
|
||||
navCss [ Css.Media.withMedia [ MediaQuery.quizEngineMobile ] styles ]
|
||||
|
||||
|
||||
{-| -}
|
||||
type alias CollapsibleConfig msg =
|
||||
{ isOpen : Bool
|
||||
, toggle : Bool -> msg
|
||||
, isTooltipOpen : Bool
|
||||
, toggleTooltip : Bool -> msg
|
||||
}
|
||||
|
||||
|
||||
{-| -}
|
||||
collapsible : CollapsibleConfig msg -> NavAttribute msg
|
||||
collapsible collapsible_ =
|
||||
NavAttribute (\config -> { config | collapsible = Just collapsible_ })
|
||||
|
||||
|
||||
{-| -}
|
||||
view : Config route msg -> List (NavAttribute msg) -> List (Entry route msg) -> Html msg
|
||||
view config navAttributes entries =
|
||||
let
|
||||
appliedNavAttributes =
|
||||
List.foldl (\(NavAttribute f) b -> f b) defaultNavAttributeConfig navAttributes
|
||||
|
||||
showNav =
|
||||
Maybe.map .isOpen appliedNavAttributes.collapsible
|
||||
|> Maybe.withDefault True
|
||||
|
||||
sidenavId =
|
||||
Maybe.withDefault defaultSideNavId appliedNavAttributes.navId
|
||||
|
||||
defaultCss =
|
||||
[ if showNav then
|
||||
case appliedNavAttributes.collapsible of
|
||||
Just _ ->
|
||||
Css.batch
|
||||
[ Css.flexBasis (Css.px 245)
|
||||
, Css.padding4 (Css.px 25) (Css.px 25) (Css.px 20) (Css.px 20)
|
||||
]
|
||||
|
||||
Nothing ->
|
||||
Css.batch
|
||||
[ Css.flexBasis (Css.px 250)
|
||||
, Css.padding (Css.px 20)
|
||||
]
|
||||
|
||||
else
|
||||
Css.flexBasis (Css.px 5)
|
||||
, flexShrink (num 0)
|
||||
, marginRight (px 20)
|
||||
, position relative
|
||||
, borderRadius (px 8)
|
||||
, backgroundColor Colors.gray96
|
||||
]
|
||||
in
|
||||
div [ Attributes.css (defaultCss ++ appliedNavAttributes.css) ]
|
||||
[ viewSkipLink config.onSkipNav
|
||||
, viewJust (viewOpenCloseButton sidenavId appliedNavAttributes.navLabel) appliedNavAttributes.collapsible
|
||||
, viewNav sidenavId config appliedNavAttributes entries showNav
|
||||
]
|
||||
|
||||
|
||||
defaultSideNavId : String
|
||||
defaultSideNavId =
|
||||
"sidenav"
|
||||
|
||||
|
||||
viewOpenCloseButton : String -> Maybe String -> CollapsibleConfig msg -> Html msg
|
||||
viewOpenCloseButton sidenavId navLabel_ { isOpen, toggle, isTooltipOpen, toggleTooltip } =
|
||||
let
|
||||
name =
|
||||
Maybe.withDefault "sidebar" navLabel_
|
||||
|
||||
( action, icon_, attributes ) =
|
||||
if isOpen then
|
||||
( "Close " ++ name
|
||||
, UiIcon.openClose
|
||||
, [ ClickableSvg.css [ Css.padding (Css.px 5) ]
|
||||
, ClickableSvg.iconForMobile UiIcon.x
|
||||
]
|
||||
)
|
||||
|
||||
else
|
||||
( "Open " ++ name
|
||||
, UiIcon.openClose
|
||||
|> Svg.withCss [ Css.transform (rotate (deg 180)) ]
|
||||
, [ ClickableSvg.withBorder
|
||||
, ClickableSvg.iconForMobile UiIcon.hamburger
|
||||
]
|
||||
)
|
||||
|
||||
trigger tooltipAttributes =
|
||||
ClickableSvg.button action
|
||||
icon_
|
||||
([ ClickableSvg.custom
|
||||
[ Aria.controls [ sidenavId ]
|
||||
, Aria.expanded isOpen
|
||||
]
|
||||
, ClickableSvg.custom tooltipAttributes
|
||||
, ClickableSvg.onClick (toggle (not isOpen))
|
||||
, ClickableSvg.tertiary
|
||||
]
|
||||
++ attributes
|
||||
)
|
||||
in
|
||||
Tooltip.view
|
||||
{ trigger = trigger
|
||||
, id = "open-close-sidebar-tooltip"
|
||||
}
|
||||
[ Tooltip.open isTooltipOpen
|
||||
, Tooltip.onToggle toggleTooltip
|
||||
, Tooltip.plaintext action
|
||||
, Tooltip.smallPadding
|
||||
, Tooltip.fitToContent
|
||||
, if isOpen then
|
||||
Tooltip.onLeft
|
||||
|
||||
else
|
||||
Tooltip.onRight
|
||||
, Tooltip.onRightForMobile
|
||||
, Tooltip.containerCss
|
||||
(if isOpen then
|
||||
[ Css.Media.withMedia [ MediaQuery.notMobile ]
|
||||
[ Css.position Css.absolute
|
||||
, Css.top Css.zero
|
||||
, Css.right Css.zero
|
||||
]
|
||||
]
|
||||
|
||||
else
|
||||
[]
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
viewNav : String -> Config route msg -> NavAttributeConfig msg -> List (Entry route msg) -> Bool -> Html msg
|
||||
viewNav sidenavId config appliedNavAttributes entries showNav =
|
||||
nav
|
||||
([ Maybe.map Aria.label appliedNavAttributes.navLabel
|
||||
, Just (Attributes.id sidenavId)
|
||||
, if showNav then
|
||||
Nothing
|
||||
|
||||
else
|
||||
Just (Attributes.css [ Css.display Css.none ])
|
||||
]
|
||||
|> List.filterMap identity
|
||||
)
|
||||
(List.map (viewSidebarEntry config []) entries)
|
||||
|
||||
|
||||
viewSkipLink : msg -> Html msg
|
||||
viewSkipLink onSkip =
|
||||
ClickableText.button "Skip to main content"
|
||||
[ ClickableText.icon UiIcon.arrowPointingRight
|
||||
, ClickableText.small
|
||||
, ClickableText.css
|
||||
[ Css.pseudoClass "not(:focus)"
|
||||
[ Style.invisibleStyle
|
||||
]
|
||||
]
|
||||
, ClickableText.onClick onSkip
|
||||
]
|
||||
|
||||
|
||||
viewSidebarEntry : Config route msg -> List Css.Style -> Entry route msg -> Html msg
|
||||
viewSidebarEntry config extraStyles entry_ =
|
||||
case entry_ of
|
||||
Entry children entryConfig ->
|
||||
if entryConfig.premiumDisplay == PremiumDisplay.PremiumLocked then
|
||||
viewLockedEntry extraStyles entryConfig
|
||||
|
||||
else if anyLinkDescendants (isCurrentRoute config) children then
|
||||
div [ Attributes.css extraStyles ]
|
||||
(styled span
|
||||
(sharedEntryStyles
|
||||
++ [ backgroundColor Colors.gray92
|
||||
, color Colors.navy
|
||||
, fontWeight bold
|
||||
, cursor default
|
||||
, marginBottom (px 10)
|
||||
]
|
||||
)
|
||||
[]
|
||||
[ text entryConfig.title ]
|
||||
:: List.map (viewSidebarEntry config [ marginLeft (px 20) ]) children
|
||||
)
|
||||
|
||||
else
|
||||
viewSidebarLeaf config extraStyles entryConfig
|
||||
|
||||
Html html_ ->
|
||||
div [ Attributes.css extraStyles ] html_
|
||||
|
||||
|
||||
isCurrentRoute : Config route msg -> EntryConfig route msg -> Bool
|
||||
isCurrentRoute config { route } =
|
||||
Maybe.map config.isCurrentRoute route
|
||||
|> Maybe.withDefault False
|
||||
|
||||
|
||||
anyLinkDescendants : (EntryConfig route msg -> Bool) -> List (Entry route msg) -> Bool
|
||||
anyLinkDescendants f children =
|
||||
List.any
|
||||
(\entry_ ->
|
||||
case entry_ of
|
||||
Entry children_ entryConfig ->
|
||||
f entryConfig || anyLinkDescendants f children_
|
||||
|
||||
Html _ ->
|
||||
False
|
||||
)
|
||||
children
|
||||
|
||||
|
||||
viewSidebarLeaf :
|
||||
Config route msg
|
||||
-> List Style
|
||||
-> EntryConfig route msg
|
||||
-> Html msg
|
||||
viewSidebarLeaf config extraStyles entryConfig =
|
||||
let
|
||||
( linkFunctionName, attributes ) =
|
||||
ClickableAttributes.toLinkAttributes
|
||||
{ routeToString = config.routeToString
|
||||
, isDisabled = False
|
||||
}
|
||||
entryConfig.clickableAttributes
|
||||
in
|
||||
Nri.Ui.styled Html.Styled.a
|
||||
("Nri-Ui-SideNav-" ++ linkFunctionName)
|
||||
(sharedEntryStyles
|
||||
++ extraStyles
|
||||
++ (if isCurrentRoute config entryConfig then
|
||||
[ backgroundColor Colors.glacier
|
||||
, color Colors.navy
|
||||
, fontWeight bold
|
||||
, visited [ color Colors.navy ]
|
||||
]
|
||||
|
||||
else
|
||||
[]
|
||||
)
|
||||
++ entryConfig.customStyles
|
||||
)
|
||||
(attributes ++ entryConfig.customAttributes)
|
||||
[ viewJust
|
||||
(\icon_ ->
|
||||
icon_
|
||||
|> Svg.withWidth (px 20)
|
||||
|> Svg.withHeight (px 20)
|
||||
|> Svg.withCss [ marginRight (px 5) ]
|
||||
|> Svg.toHtml
|
||||
)
|
||||
entryConfig.icon
|
||||
, text entryConfig.title
|
||||
]
|
||||
|
||||
|
||||
viewLockedEntry : List Style -> EntryConfig route msg -> Html msg
|
||||
viewLockedEntry extraStyles entryConfig =
|
||||
styled Html.Styled.button
|
||||
[ batch sharedEntryStyles
|
||||
, important (color Colors.gray45)
|
||||
, borderWidth zero
|
||||
, batch extraStyles
|
||||
]
|
||||
(case entryConfig.onLockedContent of
|
||||
Just event ->
|
||||
Events.onClick event :: entryConfig.customAttributes
|
||||
|
||||
Nothing ->
|
||||
entryConfig.customAttributes
|
||||
)
|
||||
[ UiIcon.premiumLock
|
||||
|> Svg.withWidth (px 17)
|
||||
|> Svg.withHeight (px 25)
|
||||
|> Svg.withCss [ marginRight (px 10), minWidth (px 17) ]
|
||||
|> Svg.toHtml
|
||||
, text entryConfig.title
|
||||
]
|
||||
|
||||
|
||||
sharedEntryStyles : List Style
|
||||
sharedEntryStyles =
|
||||
[ padding2 (px 13) (px 20)
|
||||
, Css.property "word-break" "normal"
|
||||
, Css.property "overflow-wrap" "anywhere"
|
||||
, displayFlex
|
||||
, borderRadius (px 8)
|
||||
, alignItems center
|
||||
, Fonts.baseFont
|
||||
, color Colors.navy
|
||||
, backgroundColor transparent
|
||||
, textDecoration none
|
||||
, fontSize (px 15)
|
||||
, fontWeight (int 600)
|
||||
, textAlign left
|
||||
, cursor pointer
|
||||
]
|
||||
|
||||
|
||||
|
||||
-- Entry Customization helpers
|
||||
|
||||
|
||||
{-| -}
|
||||
type alias EntryConfig route msg =
|
||||
{ icon : Maybe Svg
|
||||
, title : String
|
||||
, route : Maybe route
|
||||
, clickableAttributes : ClickableAttributes route msg
|
||||
, customAttributes : List (Html.Styled.Attribute msg)
|
||||
, customStyles : List Style
|
||||
, premiumDisplay : PremiumDisplay
|
||||
, onLockedContent : Maybe msg
|
||||
}
|
||||
|
||||
|
||||
build : String -> EntryConfig route msg
|
||||
build title =
|
||||
{ icon = Nothing
|
||||
, title = title
|
||||
, route = Nothing
|
||||
, clickableAttributes = ClickableAttributes.init
|
||||
, customAttributes = []
|
||||
, customStyles = []
|
||||
, premiumDisplay = PremiumDisplay.Free
|
||||
, onLockedContent = Nothing
|
||||
}
|
||||
|
||||
|
||||
{-| -}
|
||||
type Attribute route msg
|
||||
= Attribute (EntryConfig route msg -> EntryConfig route msg)
|
||||
|
||||
|
||||
{-| -}
|
||||
icon : Svg -> Attribute route msg
|
||||
icon icon_ =
|
||||
Attribute (\attributes -> { attributes | icon = Just icon_ })
|
||||
|
||||
|
||||
{-| -}
|
||||
premiumDisplay : PremiumDisplay -> msg -> Attribute route msg
|
||||
premiumDisplay display ifLocked =
|
||||
Attribute
|
||||
(\attributes ->
|
||||
{ attributes
|
||||
| premiumDisplay = display
|
||||
, onLockedContent = Just ifLocked
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
{-| Use this helper to add custom attributes.
|
||||
|
||||
Do NOT use this helper to add css styles, as they may not be applied the way
|
||||
you want/expect if underlying Button styles change.
|
||||
Instead, please use the `css` helper.
|
||||
|
||||
-}
|
||||
custom : List (Html.Styled.Attribute msg) -> Attribute route msg
|
||||
custom attributes =
|
||||
Attribute
|
||||
(\config ->
|
||||
{ config
|
||||
| customAttributes = List.append config.customAttributes attributes
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
{-| -}
|
||||
nriDescription : String -> Attribute route msg
|
||||
nriDescription description =
|
||||
custom [ ExtraAttributes.nriDescription description ]
|
||||
|
||||
|
||||
{-| -}
|
||||
testId : String -> Attribute route msg
|
||||
testId id_ =
|
||||
custom [ ExtraAttributes.testId id_ ]
|
||||
|
||||
|
||||
{-| -}
|
||||
id : String -> Attribute route msg
|
||||
id id_ =
|
||||
custom [ Attributes.id id_ ]
|
||||
|
||||
|
||||
{-| -}
|
||||
css : List Style -> Attribute route msg
|
||||
css styles =
|
||||
Attribute
|
||||
(\config ->
|
||||
{ config
|
||||
| customStyles = List.append config.customStyles styles
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
{-| -}
|
||||
primary : Attribute route msg
|
||||
primary =
|
||||
Attribute (\attributes -> { attributes | customStyles = [] })
|
||||
|
||||
|
||||
{-| -}
|
||||
secondary : Attribute route msg
|
||||
secondary =
|
||||
Attribute
|
||||
(\attributes ->
|
||||
{ attributes
|
||||
| customStyles =
|
||||
[ backgroundColor Colors.white
|
||||
, boxShadow3 zero (px 2) Colors.gray75
|
||||
, border3 (px 1) solid Colors.gray75
|
||||
]
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
|
||||
-- LINKING, CLICKING, and TRACKING BEHAVIOR
|
||||
|
||||
|
||||
setClickableAttributes :
|
||||
Maybe route
|
||||
-> (ClickableAttributes route msg -> ClickableAttributes route msg)
|
||||
-> Attribute route msg
|
||||
setClickableAttributes route apply =
|
||||
Attribute
|
||||
(\attributes ->
|
||||
{ attributes
|
||||
| route =
|
||||
case route of
|
||||
Just r ->
|
||||
Just r
|
||||
|
||||
Nothing ->
|
||||
attributes.route
|
||||
, clickableAttributes = apply attributes.clickableAttributes
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
{-| -}
|
||||
onClick : msg -> Attribute route msg
|
||||
onClick msg =
|
||||
setClickableAttributes Nothing (ClickableAttributes.onClick msg)
|
||||
|
||||
|
||||
{-| -}
|
||||
href : route -> Attribute route msg
|
||||
href route =
|
||||
setClickableAttributes (Just route) (ClickableAttributes.href route)
|
||||
|
||||
|
||||
{-| 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 -> Attribute route msg
|
||||
linkSpa route =
|
||||
setClickableAttributes (Just route)
|
||||
(ClickableAttributes.linkSpa route)
|
||||
|
||||
|
||||
{-| -}
|
||||
linkWithMethod : { method : String, url : route } -> Attribute route msg
|
||||
linkWithMethod config =
|
||||
setClickableAttributes (Just config.url)
|
||||
(ClickableAttributes.linkWithMethod config)
|
||||
|
||||
|
||||
{-| -}
|
||||
linkWithTracking : { track : msg, url : route } -> Attribute route msg
|
||||
linkWithTracking config =
|
||||
setClickableAttributes (Just config.url)
|
||||
(ClickableAttributes.linkWithTracking config)
|
||||
|
||||
|
||||
{-| -}
|
||||
linkExternal : String -> Attribute route msg
|
||||
linkExternal url =
|
||||
setClickableAttributes Nothing (ClickableAttributes.linkExternal url)
|
||||
|
||||
|
||||
{-| -}
|
||||
linkExternalWithTracking : { track : msg, url : String } -> Attribute route msg
|
||||
linkExternalWithTracking config =
|
||||
setClickableAttributes Nothing (ClickableAttributes.linkExternalWithTracking config)
|
@ -24,7 +24,7 @@ import Html.Styled.Events
|
||||
import Nri.Ui.Colors.Extra exposing (toCssString)
|
||||
import Nri.Ui.Colors.V1
|
||||
import Nri.Ui.CssVendorPrefix.V1 as CssVendorPrefix
|
||||
import Nri.Ui.Table.V5
|
||||
import Nri.Ui.Table.V6
|
||||
import Svg.Styled as Svg
|
||||
import Svg.Styled.Attributes as SvgAttributes
|
||||
|
||||
@ -187,7 +187,7 @@ viewLoading config state =
|
||||
tableColumns =
|
||||
List.map (buildTableColumn config.updateMsg state) config.columns
|
||||
in
|
||||
Nri.Ui.Table.V5.viewLoading
|
||||
Nri.Ui.Table.V6.viewLoading
|
||||
tableColumns
|
||||
|
||||
|
||||
@ -201,7 +201,7 @@ view config state entries =
|
||||
sorter =
|
||||
findSorter config.columns state.column
|
||||
in
|
||||
Nri.Ui.Table.V5.view
|
||||
Nri.Ui.Table.V6.view
|
||||
tableColumns
|
||||
(List.sortWith (sorter state.sortDirection) entries)
|
||||
|
||||
@ -236,13 +236,14 @@ identitySorter =
|
||||
EQ
|
||||
|
||||
|
||||
buildTableColumn : (State id -> msg) -> State id -> Column id entry msg -> Nri.Ui.Table.V5.Column entry msg
|
||||
buildTableColumn : (State id -> msg) -> State id -> Column id entry msg -> Nri.Ui.Table.V6.Column entry msg
|
||||
buildTableColumn updateMsg state (Column column) =
|
||||
Nri.Ui.Table.V5.custom
|
||||
Nri.Ui.Table.V6.custom
|
||||
{ header = viewSortHeader column.header updateMsg state column.id
|
||||
, view = column.view
|
||||
, width = Css.px (toFloat column.width)
|
||||
, cellStyles = column.cellStyles
|
||||
, sort = Nothing -- use SortableTable.V3 for better accessibility!
|
||||
}
|
||||
|
||||
|
||||
|
@ -32,15 +32,10 @@ import Nri.Ui.Colors.V1
|
||||
import Nri.Ui.CssVendorPrefix.V1 as CssVendorPrefix
|
||||
import Nri.Ui.Fonts.V1 as Fonts
|
||||
import Nri.Ui.Svg.V1
|
||||
import Nri.Ui.Table.V5
|
||||
import Nri.Ui.Table.V6 as Table exposing (SortDirection(..))
|
||||
import Nri.Ui.UiIcon.V1
|
||||
|
||||
|
||||
type SortDirection
|
||||
= Ascending
|
||||
| Descending
|
||||
|
||||
|
||||
{-| -}
|
||||
type alias Sorter a =
|
||||
SortDirection -> a -> a -> Order
|
||||
@ -194,7 +189,7 @@ viewLoading config state =
|
||||
tableColumns =
|
||||
List.map (buildTableColumn config.updateMsg state) config.columns
|
||||
in
|
||||
Nri.Ui.Table.V5.viewLoading
|
||||
Table.viewLoading
|
||||
tableColumns
|
||||
|
||||
|
||||
@ -208,7 +203,7 @@ view config state entries =
|
||||
sorter =
|
||||
findSorter config.columns state.column
|
||||
in
|
||||
Nri.Ui.Table.V5.view
|
||||
Table.view
|
||||
tableColumns
|
||||
(List.sortWith (sorter state.sortDirection) entries)
|
||||
|
||||
@ -243,13 +238,19 @@ identitySorter =
|
||||
EQ
|
||||
|
||||
|
||||
buildTableColumn : (State id -> msg) -> State id -> Column id entry msg -> Nri.Ui.Table.V5.Column entry msg
|
||||
buildTableColumn : (State id -> msg) -> State id -> Column id entry msg -> Table.Column entry msg
|
||||
buildTableColumn updateMsg state (Column column) =
|
||||
Nri.Ui.Table.V5.custom
|
||||
Table.custom
|
||||
{ header = viewSortHeader (column.sorter /= Nothing) column.header updateMsg state column.id
|
||||
, view = column.view
|
||||
, width = Css.px (toFloat column.width)
|
||||
, cellStyles = column.cellStyles
|
||||
, sort =
|
||||
if state.column == column.id then
|
||||
Just state.sortDirection
|
||||
|
||||
else
|
||||
Nothing
|
||||
}
|
||||
|
||||
|
||||
|
@ -36,13 +36,13 @@ import Accessibility.Styled as Html exposing (Html)
|
||||
import Accessibility.Styled.Aria as Aria
|
||||
import Css exposing (Color, Style)
|
||||
import Css.Global as Global
|
||||
import Css.Media
|
||||
import Html.Styled.Attributes as Attributes
|
||||
import Html.Styled.Events as Events
|
||||
import Nri.Ui.Colors.Extra exposing (toCssString)
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.Fonts.V1 as Fonts
|
||||
import Nri.Ui.Html.Attributes.V2 as Extra
|
||||
import Nri.Ui.MediaQuery.V1 as MediaQuery
|
||||
import Nri.Ui.Svg.V1 exposing (Svg)
|
||||
import Svg.Styled as Svg
|
||||
import Svg.Styled.Attributes as SvgAttributes
|
||||
@ -373,6 +373,4 @@ stroke color =
|
||||
|
||||
transition : String -> Css.Style
|
||||
transition transitionRules =
|
||||
Css.Media.withMediaQuery
|
||||
[ "(prefers-reduced-motion: no-preference)" ]
|
||||
[ Css.property "transition" transitionRules ]
|
||||
MediaQuery.anyMotion [ Css.property "transition" transitionRules ]
|
||||
|
298
src/Nri/Ui/Table/V6.elm
Normal file
298
src/Nri/Ui/Table/V6.elm
Normal file
@ -0,0 +1,298 @@
|
||||
module Nri.Ui.Table.V6 exposing
|
||||
( Column, SortDirection(..), custom, string
|
||||
, view, viewWithoutHeader
|
||||
, viewLoading, viewLoadingWithoutHeader
|
||||
)
|
||||
|
||||
{-| Upgrading from V5:
|
||||
|
||||
- The columns take an additional `sort` property that allows
|
||||
you to specify ARIA sorting
|
||||
|
||||
@docs Column, SortDirection, custom, string
|
||||
|
||||
@docs view, viewWithoutHeader
|
||||
|
||||
@docs viewLoading, viewLoadingWithoutHeader
|
||||
|
||||
-}
|
||||
|
||||
import Accessibility.Styled.Style as Style
|
||||
import Css exposing (..)
|
||||
import Css.Animations
|
||||
import Html.Styled as Html exposing (..)
|
||||
import Html.Styled.Attributes as Attributes exposing (css)
|
||||
import Nri.Ui.Colors.V1 exposing (..)
|
||||
import Nri.Ui.Fonts.V1 exposing (baseFont)
|
||||
|
||||
|
||||
{-| Closed representation of how to render the header and cells of a column
|
||||
in the table
|
||||
-}
|
||||
type Column data msg
|
||||
= Column (Html msg) (data -> Html msg) Style (data -> List Style) (Maybe SortDirection)
|
||||
|
||||
|
||||
{-| Which direction is a table column sorted? Only set these on columns that
|
||||
actually have an explicit sort!
|
||||
-}
|
||||
type SortDirection
|
||||
= Ascending
|
||||
| Descending
|
||||
|
||||
|
||||
{-| A column that renders some aspect of a value as text
|
||||
-}
|
||||
string :
|
||||
{ header : String
|
||||
, value : data -> String
|
||||
, width : LengthOrAuto compatible
|
||||
, cellStyles : data -> List Style
|
||||
, sort : Maybe SortDirection
|
||||
}
|
||||
-> Column data msg
|
||||
string { header, value, width, cellStyles, sort } =
|
||||
Column (Html.text header) (value >> Html.text) (Css.width width) cellStyles sort
|
||||
|
||||
|
||||
{-| A column that renders however you want it to
|
||||
-}
|
||||
custom :
|
||||
{ header : Html msg
|
||||
, view : data -> Html msg
|
||||
, width : LengthOrAuto compatible
|
||||
, cellStyles : data -> List Style
|
||||
, sort : Maybe SortDirection
|
||||
}
|
||||
-> Column data msg
|
||||
custom options =
|
||||
Column options.header options.view (Css.width options.width) options.cellStyles options.sort
|
||||
|
||||
|
||||
|
||||
-- VIEW
|
||||
|
||||
|
||||
{-| Displays a table of data without a header row
|
||||
-}
|
||||
viewWithoutHeader : List (Column data msg) -> List data -> Html msg
|
||||
viewWithoutHeader columns =
|
||||
tableWithoutHeader [] columns (viewRow columns)
|
||||
|
||||
|
||||
{-| Displays a table of data based on the provided column definitions
|
||||
-}
|
||||
view : List (Column data msg) -> List data -> Html msg
|
||||
view columns =
|
||||
tableWithHeader [] columns (viewRow columns)
|
||||
|
||||
|
||||
viewRow : List (Column data msg) -> data -> Html msg
|
||||
viewRow columns data =
|
||||
tr
|
||||
[ css rowStyles ]
|
||||
(List.map (viewColumn data) columns)
|
||||
|
||||
|
||||
viewColumn : data -> Column data msg -> Html msg
|
||||
viewColumn data (Column _ renderer width cellStyles _) =
|
||||
td
|
||||
[ css ([ width, verticalAlign middle ] ++ cellStyles data)
|
||||
]
|
||||
[ renderer data ]
|
||||
|
||||
|
||||
|
||||
-- VIEW LOADING
|
||||
|
||||
|
||||
{-| Display a table with the given columns but instead of data, show blocked
|
||||
out text with an interesting animation. This view lets the user know that
|
||||
data is on its way and what it will look like when it arrives.
|
||||
-}
|
||||
viewLoading : List (Column data msg) -> Html msg
|
||||
viewLoading columns =
|
||||
tableWithHeader loadingTableStyles columns (viewLoadingRow columns) (List.range 0 8)
|
||||
|
||||
|
||||
{-| Display the loading table without a header row
|
||||
-}
|
||||
viewLoadingWithoutHeader : List (Column data msg) -> Html msg
|
||||
viewLoadingWithoutHeader columns =
|
||||
tableWithoutHeader loadingTableStyles columns (viewLoadingRow columns) (List.range 0 8)
|
||||
|
||||
|
||||
viewLoadingRow : List (Column data msg) -> Int -> Html msg
|
||||
viewLoadingRow columns index =
|
||||
tr
|
||||
[ css rowStyles ]
|
||||
(List.indexedMap (viewLoadingColumn index) columns)
|
||||
|
||||
|
||||
viewLoadingColumn : Int -> Int -> Column data msg -> Html msg
|
||||
viewLoadingColumn rowIndex colIndex (Column _ _ width _ _) =
|
||||
td
|
||||
[ css (stylesLoadingColumn rowIndex colIndex width ++ [ verticalAlign middle ] ++ loadingCellStyles)
|
||||
]
|
||||
[ span [ css loadingContentStyles ] [] ]
|
||||
|
||||
|
||||
stylesLoadingColumn : Int -> Int -> Style -> List Style
|
||||
stylesLoadingColumn rowIndex colIndex width =
|
||||
[ width
|
||||
, property "animation-delay" (String.fromFloat (toFloat (rowIndex + colIndex) * 0.1) ++ "s")
|
||||
]
|
||||
|
||||
|
||||
|
||||
-- HELP
|
||||
|
||||
|
||||
tableWithoutHeader : List Style -> List (Column data msg) -> (a -> Html msg) -> List a -> Html msg
|
||||
tableWithoutHeader styles columns toRow data =
|
||||
table styles
|
||||
[ thead [] [ tr Style.invisible (List.map tableRowHeader columns) ]
|
||||
, tableBody toRow data
|
||||
]
|
||||
|
||||
|
||||
tableWithHeader : List Style -> List (Column data msg) -> (a -> Html msg) -> List a -> Html msg
|
||||
tableWithHeader styles columns toRow data =
|
||||
table styles
|
||||
[ tableHeader columns
|
||||
, tableBody toRow data
|
||||
]
|
||||
|
||||
|
||||
table : List Style -> List (Html msg) -> Html msg
|
||||
table styles =
|
||||
Html.table [ css (styles ++ tableStyles) ]
|
||||
|
||||
|
||||
tableHeader : List (Column data msg) -> Html msg
|
||||
tableHeader columns =
|
||||
thead []
|
||||
[ tr [ css headersStyles ]
|
||||
(List.map tableRowHeader columns)
|
||||
]
|
||||
|
||||
|
||||
tableRowHeader : Column data msg -> Html msg
|
||||
tableRowHeader (Column header _ width _ sort) =
|
||||
th
|
||||
[ Attributes.scope "col"
|
||||
, css (width :: headerStyles)
|
||||
, Attributes.attribute "aria-sort" <|
|
||||
case sort of
|
||||
Nothing ->
|
||||
"none"
|
||||
|
||||
Just Ascending ->
|
||||
"ascending"
|
||||
|
||||
Just Descending ->
|
||||
"descending"
|
||||
]
|
||||
[ header ]
|
||||
|
||||
|
||||
tableBody : (a -> Html msg) -> List a -> Html msg
|
||||
tableBody toRow items =
|
||||
tbody [] (List.map toRow items)
|
||||
|
||||
|
||||
|
||||
-- STYLES
|
||||
|
||||
|
||||
headersStyles : List Style
|
||||
headersStyles =
|
||||
[ borderBottom3 (px 3) solid gray75
|
||||
, height (px 45)
|
||||
, fontSize (px 15)
|
||||
]
|
||||
|
||||
|
||||
headerStyles : List Style
|
||||
headerStyles =
|
||||
[ padding4 (px 15) (px 12) (px 11) (px 12)
|
||||
, textAlign left
|
||||
, fontWeight bold
|
||||
]
|
||||
|
||||
|
||||
rowStyles : List Style
|
||||
rowStyles =
|
||||
[ height (px 45)
|
||||
, fontSize (px 14)
|
||||
, color gray20
|
||||
, pseudoClass "nth-child(odd)"
|
||||
[ backgroundColor gray96 ]
|
||||
]
|
||||
|
||||
|
||||
loadingContentStyles : List Style
|
||||
loadingContentStyles =
|
||||
[ width (pct 100)
|
||||
, display inlineBlock
|
||||
, height (Css.em 1)
|
||||
, borderRadius (Css.em 1)
|
||||
, backgroundColor gray75
|
||||
]
|
||||
|
||||
|
||||
loadingCellStyles : List Style
|
||||
loadingCellStyles =
|
||||
[ batch flashAnimation
|
||||
, padding2 (px 14) (px 10)
|
||||
]
|
||||
|
||||
|
||||
loadingTableStyles : List Style
|
||||
loadingTableStyles =
|
||||
fadeInAnimation
|
||||
|
||||
|
||||
tableStyles : List Style
|
||||
tableStyles =
|
||||
[ borderCollapse collapse
|
||||
, baseFont
|
||||
, Css.width (Css.pct 100)
|
||||
]
|
||||
|
||||
|
||||
flash : Css.Animations.Keyframes {}
|
||||
flash =
|
||||
Css.Animations.keyframes
|
||||
[ ( 0, [ Css.Animations.opacity (Css.num 0.6) ] )
|
||||
, ( 50, [ Css.Animations.opacity (Css.num 0.2) ] )
|
||||
, ( 100, [ Css.Animations.opacity (Css.num 0.6) ] )
|
||||
]
|
||||
|
||||
|
||||
fadeIn : Css.Animations.Keyframes {}
|
||||
fadeIn =
|
||||
Css.Animations.keyframes
|
||||
[ ( 0, [ Css.Animations.opacity (Css.num 0) ] )
|
||||
, ( 100, [ Css.Animations.opacity (Css.num 1) ] )
|
||||
]
|
||||
|
||||
|
||||
flashAnimation : List Css.Style
|
||||
flashAnimation =
|
||||
[ animationName flash
|
||||
, property "animation-duration" "2s"
|
||||
, property "animation-iteration-count" "infinite"
|
||||
, opacity (num 0.6)
|
||||
]
|
||||
|
||||
|
||||
fadeInAnimation : List Css.Style
|
||||
fadeInAnimation =
|
||||
[ animationName fadeIn
|
||||
, property "animation-duration" "0.4s"
|
||||
, property "animation-delay" "0.2s"
|
||||
, property "animation-fill-mode" "forwards"
|
||||
, animationIterationCount (int 1)
|
||||
, opacity (num 0)
|
||||
]
|
@ -27,7 +27,7 @@ module Nri.Ui.Text.V6 exposing
|
||||
|
||||
## Headings
|
||||
|
||||
You're in the wrong place! Headings live in Nri.Ui.Heading.V2.
|
||||
You're in the wrong place! Headings live in Nri.Ui.Heading.V3.
|
||||
|
||||
|
||||
## Paragraph styles
|
||||
|
@ -1,6 +1,6 @@
|
||||
module Nri.Ui.TextInput.V7 exposing
|
||||
( view, generateId
|
||||
, number, float, text, newPassword, currentPassword, email, search
|
||||
, number, float, text, newPassword, currentPassword, email, search, addressLevel2, addressLine1, familyName, givenName, organization, organizationTitle, postalCode, sex, tel
|
||||
, readOnlyText
|
||||
, value, map
|
||||
, onFocus, onBlur, onEnter
|
||||
@ -27,7 +27,7 @@ module Nri.Ui.TextInput.V7 exposing
|
||||
|
||||
### Input types
|
||||
|
||||
@docs number, float, text, newPassword, currentPassword, email, search
|
||||
@docs number, float, text, newPassword, currentPassword, email, search, addressLevel2, addressLine1, familyName, givenName, organization, organizationTitle, postalCode, sex, tel
|
||||
@docs readOnlyText
|
||||
|
||||
|
||||
@ -269,6 +269,177 @@ search onInput_ =
|
||||
)
|
||||
|
||||
|
||||
{-| An input that allows given-name entry
|
||||
-}
|
||||
givenName : (String -> msg) -> Attribute String msg
|
||||
givenName onInput_ =
|
||||
Attribute
|
||||
{ emptyEventsAndValues
|
||||
| toString = Just identity
|
||||
, fromString = Just identity
|
||||
, onInput = Just (identity >> onInput_)
|
||||
}
|
||||
(\config ->
|
||||
{ config
|
||||
| fieldType = Just "text"
|
||||
, inputMode = Nothing
|
||||
, autocomplete = Just "given-name"
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
{-| An input that allows family-name entry
|
||||
-}
|
||||
familyName : (String -> msg) -> Attribute String msg
|
||||
familyName onInput_ =
|
||||
Attribute
|
||||
{ emptyEventsAndValues
|
||||
| toString = Just identity
|
||||
, fromString = Just identity
|
||||
, onInput = Just (identity >> onInput_)
|
||||
}
|
||||
(\config ->
|
||||
{ config
|
||||
| fieldType = Just "text"
|
||||
, inputMode = Nothing
|
||||
, autocomplete = Just "family-name"
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
{-| An input that allows organization entry
|
||||
-}
|
||||
organization : (String -> msg) -> Attribute String msg
|
||||
organization onInput_ =
|
||||
Attribute
|
||||
{ emptyEventsAndValues
|
||||
| toString = Just identity
|
||||
, fromString = Just identity
|
||||
, onInput = Just (identity >> onInput_)
|
||||
}
|
||||
(\config ->
|
||||
{ config
|
||||
| fieldType = Just "text"
|
||||
, inputMode = Nothing
|
||||
, autocomplete = Just "organization"
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
{-| An input that allows organization-title entry
|
||||
-}
|
||||
organizationTitle : (String -> msg) -> Attribute String msg
|
||||
organizationTitle onInput_ =
|
||||
Attribute
|
||||
{ emptyEventsAndValues
|
||||
| toString = Just identity
|
||||
, fromString = Just identity
|
||||
, onInput = Just (identity >> onInput_)
|
||||
}
|
||||
(\config ->
|
||||
{ config
|
||||
| fieldType = Just "text"
|
||||
, inputMode = Nothing
|
||||
, autocomplete = Just "organization-title"
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
{-| An input that allows address-line1 entry
|
||||
-}
|
||||
addressLine1 : (String -> msg) -> Attribute String msg
|
||||
addressLine1 onInput_ =
|
||||
Attribute
|
||||
{ emptyEventsAndValues
|
||||
| toString = Just identity
|
||||
, fromString = Just identity
|
||||
, onInput = Just (identity >> onInput_)
|
||||
}
|
||||
(\config ->
|
||||
{ config
|
||||
| fieldType = Just "text"
|
||||
, inputMode = Nothing
|
||||
, autocomplete = Just "address-line1"
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
{-| An input that allows address-level2 entry
|
||||
-}
|
||||
addressLevel2 : (String -> msg) -> Attribute String msg
|
||||
addressLevel2 onInput_ =
|
||||
Attribute
|
||||
{ emptyEventsAndValues
|
||||
| toString = Just identity
|
||||
, fromString = Just identity
|
||||
, onInput = Just (identity >> onInput_)
|
||||
}
|
||||
(\config ->
|
||||
{ config
|
||||
| fieldType = Just "text"
|
||||
, inputMode = Nothing
|
||||
, autocomplete = Just "address-level2"
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
{-| An input that allows postal-code entry
|
||||
-}
|
||||
postalCode : (String -> msg) -> Attribute String msg
|
||||
postalCode onInput_ =
|
||||
Attribute
|
||||
{ emptyEventsAndValues
|
||||
| toString = Just identity
|
||||
, fromString = Just identity
|
||||
, onInput = Just (identity >> onInput_)
|
||||
}
|
||||
(\config ->
|
||||
{ config
|
||||
| fieldType = Just "text"
|
||||
, inputMode = Nothing
|
||||
, autocomplete = Just "postal-code"
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
{-| An input that allows tel entry
|
||||
-}
|
||||
tel : (String -> msg) -> Attribute String msg
|
||||
tel onInput_ =
|
||||
Attribute
|
||||
{ emptyEventsAndValues
|
||||
| toString = Just identity
|
||||
, fromString = Just identity
|
||||
, onInput = Just (identity >> onInput_)
|
||||
}
|
||||
(\config ->
|
||||
{ config
|
||||
| fieldType = Just "tel"
|
||||
, inputMode = Just "tel"
|
||||
, autocomplete = Just "tel"
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
{-| An input that allows sex entry
|
||||
-}
|
||||
sex : (String -> msg) -> Attribute String msg
|
||||
sex onInput_ =
|
||||
Attribute
|
||||
{ emptyEventsAndValues
|
||||
| toString = Just identity
|
||||
, fromString = Just identity
|
||||
, onInput = Just (identity >> onInput_)
|
||||
}
|
||||
(\config ->
|
||||
{ config
|
||||
| fieldType = Just "text"
|
||||
, inputMode = Nothing
|
||||
, autocomplete = Just "sex"
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
{-| -}
|
||||
value : value -> Attribute value msg
|
||||
value value_ =
|
||||
|
@ -1,5 +1,5 @@
|
||||
module Nri.Ui.UiIcon.V1 exposing
|
||||
( seeMore, openClose, download, sort, gear, flipper
|
||||
( seeMore, openClose, download, sort, gear, flipper, hamburger
|
||||
, archive, unarchive
|
||||
, playInCircle, pauseInCircle, stopInCircle
|
||||
, play, skip
|
||||
@ -20,7 +20,7 @@ module Nri.Ui.UiIcon.V1 exposing
|
||||
, flag, star, starFilled, starOutline
|
||||
, equals, plus, null
|
||||
, key, lock, premiumLock
|
||||
, badge, tada
|
||||
, badge, tada, count
|
||||
, bold, italic, underline, list, link, undo, redo
|
||||
, home, library
|
||||
, search, searchInCicle
|
||||
@ -29,11 +29,12 @@ module Nri.Ui.UiIcon.V1 exposing
|
||||
, openInNewTab, sync
|
||||
, school, highSchool, company, homeSchool, graduateCap
|
||||
, flagUs, globe
|
||||
, info
|
||||
)
|
||||
|
||||
{-| How to add new icons: <https://paper.dropbox.com/doc/How-to-create-a-new-SVG-icon-for-use-in-Elm--Ay9uhSLfGUAix0ERIiJ0Dm8dAg-8WNqtARdr4EgjmYEHPeYD>
|
||||
|
||||
@docs seeMore, openClose, download, sort, gear, flipper
|
||||
@docs seeMore, openClose, download, sort, gear, flipper, hamburger
|
||||
@docs archive, unarchive
|
||||
@docs playInCircle, pauseInCircle, stopInCircle
|
||||
@docs play, skip
|
||||
@ -54,7 +55,7 @@ module Nri.Ui.UiIcon.V1 exposing
|
||||
@docs flag, star, starFilled, starOutline
|
||||
@docs equals, plus, null
|
||||
@docs key, lock, premiumLock
|
||||
@docs badge, tada
|
||||
@docs badge, tada, count
|
||||
@docs bold, italic, underline, list, link, undo, redo
|
||||
@docs home, library
|
||||
@docs search, searchInCicle
|
||||
@ -63,6 +64,7 @@ module Nri.Ui.UiIcon.V1 exposing
|
||||
@docs openInNewTab, sync
|
||||
@docs school, highSchool, company, homeSchool, graduateCap
|
||||
@docs flagUs, globe
|
||||
@docs info
|
||||
|
||||
import Html.Styled exposing (..)
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
@ -179,6 +181,17 @@ copyToClipboard =
|
||||
]
|
||||
|
||||
|
||||
{-| -}
|
||||
info : Nri.Ui.Svg.V1.Svg
|
||||
info =
|
||||
Nri.Ui.Svg.V1.init "0 0 25 25"
|
||||
[ Svg.path [ Attributes.d "M12.5,25 C5.59644063,25 0,19.4035594 0,12.5 C0,5.59644063 5.59644063,0 12.5,0 C19.4035594,0 25,5.59644063 25,12.5 C25,19.4035594 19.4035594,25 12.5,25 Z M12.5,23 C18.2989899,23 23,18.2989899 23,12.5 C23,6.70101013 18.2989899,2 12.5,2 C6.70101013,2 2,6.70101013 2,12.5 C2,18.2989899 6.70101013,23 12.5,23 Z" ] []
|
||||
, Svg.g
|
||||
[ Attributes.transform "translate(1, 0)" ]
|
||||
[ Svg.path [ Attributes.d "M13.9802 17.28H9.24023V16.7325C9.37023 16.7225 9.49773 16.71 9.62273 16.695C9.74773 16.68 9.85523 16.655 9.94523 16.62C10.1052 16.56 10.2177 16.475 10.2827 16.365C10.3477 16.25 10.3802 16.1 10.3802 15.915V11.55C10.3802 11.375 10.3402 11.2225 10.2602 11.0925C10.1802 10.9575 10.0802 10.85 9.96023 10.77C9.87023 10.71 9.73273 10.6525 9.54773 10.5975C9.36773 10.5425 9.20273 10.5075 9.05273 10.4925V9.94504L12.7277 9.75004L12.8402 9.86254V15.8175C12.8402 15.9925 12.8777 16.1425 12.9527 16.2675C13.0277 16.3875 13.1352 16.4775 13.2752 16.5375C13.3752 16.5825 13.4852 16.6225 13.6052 16.6575C13.7252 16.6925 13.8502 16.7175 13.9802 16.7325V17.28ZM12.8852 7.05004C12.8852 7.43004 12.7377 7.75504 12.4427 8.02504C12.1527 8.29004 11.8077 8.42254 11.4077 8.42254C11.0027 8.42254 10.6527 8.29004 10.3577 8.02504C10.0677 7.75504 9.92273 7.43004 9.92273 7.05004C9.92273 6.67004 10.0677 6.34504 10.3577 6.07504C10.6527 5.80504 11.0027 5.67004 11.4077 5.67004C11.8127 5.67004 12.1602 5.80504 12.4502 6.07504C12.7402 6.34504 12.8852 6.67004 12.8852 7.05004Z" ] [] ]
|
||||
]
|
||||
|
||||
|
||||
{-| -}
|
||||
performance : Nri.Ui.Svg.V1.Svg
|
||||
performance =
|
||||
@ -217,10 +230,17 @@ download =
|
||||
{-| -}
|
||||
edit : Nri.Ui.Svg.V1.Svg
|
||||
edit =
|
||||
Nri.Ui.Svg.V1.init "0 0 30 30"
|
||||
[ Svg.path [ Attributes.d "M27.3,7.9l-5.2-5.2l2.3-2.3c0.5-0.5,1.2-0.5,1.7,0L29.7,4c0.5,0.5,0.5,1.2,0,1.7L27.3,7.9z M25.9,9.4L8.6,26.6l-5.2-5.2L20.6,4.1L25.9,9.4z M0,30l1.9-7L7,28.1L0,30z" ] []
|
||||
, Svg.path [ Attributes.fill "none", Attributes.d "M-753.8-401V715h1024V-401H-753.8z" ] []
|
||||
, Svg.path [ Attributes.fill "none", Attributes.d "M-775.9-385.9v1116h1024v-1116L-775.9-385.9L-775.9-385.9z" ] []
|
||||
Nri.Ui.Svg.V1.init "0 0 95 95"
|
||||
[ Svg.path
|
||||
[ Attributes.d "M93.7748134,12.5537834 C92.2748134,10.3545834 90.4740134,8.2529834 88.4740134,6.2529834 C86.6732134,4.5537834 84.0756134,2.5537834 82.2748134,1.3545834 C79.2748134,-0.747016601 75.1732134,-0.344616601 72.6732134,2.1553634 L8.9742134,65.7533634 C8.7749934,65.9525834 8.5757734,66.2533634 8.4742134,66.5541434 L0.1734134,90.1561434 C-0.2250266,91.4569434 0.0718534003,92.8553434 0.9741934,93.7577434 C1.6734134,94.4569634 2.4741934,94.7577434 3.3725934,94.7577434 C3.7710334,94.7577434 4.1733734,94.6561834 4.5717934,94.5585234 L28.0717934,86.2577234 C28.3725734,86.1561634 28.6733534,85.9569434 28.8725734,85.7577234 L92.6735734,21.9567234 C95.2751734,19.4567234 95.6735734,15.4567234 93.7751734,12.5544234 L93.7748134,12.5537834 Z"
|
||||
, Attributes.fill "#none"
|
||||
]
|
||||
[]
|
||||
, Svg.path
|
||||
[ Attributes.d "M12.3728134,68.6557834 C17.7712134,72.3549834 22.3728134,76.9565834 26.0718134,82.3547834 L12.3728134,87.1555834 C11.8728134,86.1555834 11.2712134,85.1555834 10.3728134,84.2571834 C9.4743734,83.3587434 8.4744134,82.7571834 7.4744134,82.2571834 L12.3728134,68.6557834 Z"
|
||||
, Attributes.fill "#FFFFFF"
|
||||
]
|
||||
[]
|
||||
]
|
||||
|
||||
|
||||
@ -903,6 +923,37 @@ pauseInCircle =
|
||||
]
|
||||
|
||||
|
||||
{-| -}
|
||||
hamburger : Nri.Ui.Svg.V1.Svg
|
||||
hamburger =
|
||||
Nri.Ui.Svg.V1.init "0 0 25 25"
|
||||
[ Svg.rect
|
||||
[ Attributes.x "0"
|
||||
, Attributes.y "0"
|
||||
, Attributes.width "25"
|
||||
, Attributes.height "5"
|
||||
, Attributes.rx "2.5"
|
||||
]
|
||||
[]
|
||||
, Svg.rect
|
||||
[ Attributes.x "0"
|
||||
, Attributes.y "10"
|
||||
, Attributes.width "25"
|
||||
, Attributes.height "5"
|
||||
, Attributes.rx "2.5"
|
||||
]
|
||||
[]
|
||||
, Svg.rect
|
||||
[ Attributes.x "0"
|
||||
, Attributes.y "20"
|
||||
, Attributes.width "25"
|
||||
, Attributes.height "5"
|
||||
, Attributes.rx "2.5"
|
||||
]
|
||||
[]
|
||||
]
|
||||
|
||||
|
||||
{-| -}
|
||||
equals : Nri.Ui.Svg.V1.Svg
|
||||
equals =
|
||||
@ -1346,7 +1397,7 @@ checklistComplete =
|
||||
{-| -}
|
||||
openBook : Nri.Ui.Svg.V1.Svg
|
||||
openBook =
|
||||
Nri.Ui.Svg.V1.init "0 0 16 13"
|
||||
Nri.Ui.Svg.V1.init "0 0 15 12"
|
||||
[ Svg.g [ Attributes.transform "translate(0.256349, 0.281480)" ]
|
||||
[ Svg.path [ Attributes.d "M5.97967784,7.68594033 L6.3357413,7.774016 L6.3357413,8.297421 C4.90871699,7.91726562 3.51632767,7.87765319 2.08989378,8.17910991 L1.7325363,8.26158 L1.7325363,7.737499 C3.16515353,7.37982238 4.55798757,7.36210421 5.97967784,7.68594033 L5.97967784,7.68594033 Z" ] []
|
||||
, Svg.path [ Attributes.d "M5.97967784,6.20834789 L6.3357413,6.296302 L6.3357413,6.820381 C4.90871699,6.43960069 3.51632767,6.40051534 2.08989378,6.70152673 L1.7325363,6.783864 L1.7325363,6.26046 C3.16515353,5.90153631 4.55798757,5.88487164 5.97967784,6.20834789 L5.97967784,6.20834789 Z" ] []
|
||||
@ -1533,6 +1584,16 @@ tada =
|
||||
]
|
||||
|
||||
|
||||
{-| -}
|
||||
count : Nri.Ui.Svg.V1.Svg
|
||||
count =
|
||||
Nri.Ui.Svg.V1.init "0 0 75 75"
|
||||
[ Svg.g []
|
||||
[ Svg.path [ Attributes.d "M56.2502,0 L18.7502,0 C13.7775,0 9.008,1.9766 5.4922,5.4922 C1.9766,9.0078 0,13.7774 0,18.7502 L0,56.2502 C0,61.2229 1.9766,65.9924 5.4922,69.5082 C9.0078,73.0238 13.7774,75.0004 18.7502,75.0004 L56.2502,75.0004 C61.2229,75.0004 65.9924,73.0238 69.5082,69.5082 C73.0238,65.9926 75.0004,61.223 75.0004,56.2502 L75.0004,18.7502 C75.0004,13.7775 73.0238,9.008 69.5082,5.4922 C65.9926,1.9766 61.223,0 56.2502,0 Z M68.7502,56.25 C68.7502,59.5664 67.4338,62.7461 65.09,65.0898 C62.7462,67.4335 59.5666,68.75 56.2502,68.75 L18.7502,68.75 C11.8479,68.75 6.2502,63.1523 6.2502,56.25 L6.2502,18.75 C6.2502,11.8477 11.8479,6.25 18.7502,6.25 L56.2502,6.25 C59.5666,6.25 62.7463,7.5664 65.09,9.9102 C67.4337,12.254 68.7502,15.4336 68.7502,18.75 L68.7502,56.25 Z M57.0942,25.312 L52.0942,25.312 L53.1254,20.2495 C53.45352,18.5229 52.32071,16.8589 50.5942,16.5307 C48.86769,16.2025 47.2036,17.33539 46.8754,19.0619 L45.6879,25.3119 L33.9689,25.3119 L34.9689,20.2494 C35.29702,18.5228 34.16421,16.8588 32.4377,16.5306 C30.71119,16.2024 29.0471,17.33529 28.7189,19.0618 L27.5314,25.3118 L21.2814,25.3118 C19.5548,25.3118 18.1564,26.7102 18.1564,28.4368 C18.1564,30.1634 19.5548,31.5618 21.2814,31.5618 L26.2814,31.5618 L23.9689,43.4368 L17.7189,43.4368 C15.9923,43.4368 14.5939,44.8352 14.5939,46.5618 C14.5939,48.2884 15.9923,49.6868 17.7189,49.6868 L22.7189,49.6868 L21.87515,54.7493 C21.71109,55.56571 21.879056,56.4134 22.33999,57.1087 C22.80483,57.80011 23.52749,58.2767 24.34389,58.4368 L25.00014,58.4368 C26.51964,58.464144 27.83604,57.3977 28.12514,55.9056 L29.31264,49.6556 L41.09364,49.6556 L40.09364,54.7181 C39.92958,55.53451 40.097546,56.3822 40.55848,57.0775 C41.02332,57.76891 41.74598,58.2455 42.56238,58.4056 L43.15613,58.4056 C44.67563,58.432944 45.99203,57.3665 46.28113,55.8744 L47.46863,49.6244 L53.71863,49.6244 C55.44523,49.6244 56.84363,48.226 56.84363,46.4994 C56.84363,44.7728 55.44523,43.3744 53.71863,43.3744 L48.71863,43.3744 L51.03113,31.4994 L57.28113,31.4994 C59.00773,31.4994 60.40613,30.101 60.40613,28.3744 C60.40613,26.6478 59.00773,25.2494 57.28113,25.2494 L57.0942,25.312 Z M42.2192,43.437 L30.4692,43.437 L32.7817,31.562 L44.5317,31.562 L42.2192,43.437 Z" ] []
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
{-| -}
|
||||
openInNewTab : Nri.Ui.Svg.V1.Svg
|
||||
openInNewTab =
|
||||
|
@ -15,10 +15,10 @@ import Html.Styled.Attributes exposing (..)
|
||||
import Http
|
||||
import Json.Decode as Decode
|
||||
import Nri.Ui.CssVendorPrefix.V1 as VendorPrefixed
|
||||
import Nri.Ui.Heading.V2 as Heading
|
||||
import Nri.Ui.Heading.V3 as Heading
|
||||
import Nri.Ui.MediaQuery.V1 exposing (mobile)
|
||||
import Nri.Ui.Page.V3 as Page
|
||||
import Nri.Ui.SideNav.V3 as SideNav
|
||||
import Nri.Ui.SideNav.V4 as SideNav
|
||||
import Nri.Ui.Sprite.V1 as Sprite
|
||||
import Nri.Ui.UiIcon.V1 as UiIcon
|
||||
import Routes
|
||||
@ -36,6 +36,8 @@ type alias Model key =
|
||||
route : Route
|
||||
, previousRoute : Maybe Route
|
||||
, moduleStates : Dict String (Example Examples.State Examples.Msg)
|
||||
, isSideNavOpen : Bool
|
||||
, openTooltip : Maybe TooltipId
|
||||
, navigationKey : key
|
||||
, elliePackageDependencies : Result Http.Error (Dict String String)
|
||||
}
|
||||
@ -51,6 +53,8 @@ init () url key =
|
||||
( { route = Routes.fromLocation moduleStates url
|
||||
, previousRoute = Nothing
|
||||
, moduleStates = moduleStates
|
||||
, isSideNavOpen = True
|
||||
, openTooltip = Nothing
|
||||
, navigationKey = key
|
||||
, elliePackageDependencies = Ok Dict.empty
|
||||
}
|
||||
@ -62,12 +66,18 @@ init () url key =
|
||||
)
|
||||
|
||||
|
||||
type TooltipId
|
||||
= SideNavOpenCloseTooltip
|
||||
|
||||
|
||||
type Msg
|
||||
= UpdateModuleStates String Examples.Msg
|
||||
| OnUrlRequest Browser.UrlRequest
|
||||
| OnUrlChange Url
|
||||
| ChangeRoute Route
|
||||
| SkipToMainContent
|
||||
| ToggleSideNav Bool
|
||||
| ToggleTooltip TooltipId Bool
|
||||
| LoadedPackages (Result Http.Error (Dict String String))
|
||||
| Focused (Result Browser.Dom.Error ())
|
||||
|
||||
@ -125,6 +135,15 @@ update action model =
|
||||
, FocusOn "maincontent"
|
||||
)
|
||||
|
||||
ToggleSideNav isOpen ->
|
||||
( { model | isSideNavOpen = isOpen }, None )
|
||||
|
||||
ToggleTooltip tooltipId True ->
|
||||
( { model | openTooltip = Just tooltipId }, None )
|
||||
|
||||
ToggleTooltip _ False ->
|
||||
( { model | openTooltip = Nothing }, None )
|
||||
|
||||
LoadedPackages newPackagesResult ->
|
||||
let
|
||||
-- Ellie gets really slow to compile if we include all the packages, unfortunately!
|
||||
@ -280,10 +299,7 @@ viewCategory model category =
|
||||
)
|
||||
|
||||
|
||||
withSideNav :
|
||||
{ model | route : Route, moduleStates : Dict String (Example Examples.State Examples.Msg) }
|
||||
-> Html Msg
|
||||
-> Html Msg
|
||||
withSideNav : Model key -> Html Msg -> Html Msg
|
||||
withSideNav model content =
|
||||
Html.div
|
||||
[ css
|
||||
@ -333,10 +349,8 @@ viewPreviews containerId navConfig examples =
|
||||
]
|
||||
|
||||
|
||||
navigation :
|
||||
{ model | route : Route, moduleStates : Dict String (Example Examples.State Examples.Msg) }
|
||||
-> Html Msg
|
||||
navigation { moduleStates, route } =
|
||||
navigation : Model key -> Html Msg
|
||||
navigation { moduleStates, route, isSideNavOpen, openTooltip } =
|
||||
let
|
||||
examples =
|
||||
Dict.values moduleStates
|
||||
@ -370,6 +384,14 @@ navigation { moduleStates, route } =
|
||||
[ VendorPrefixed.value "position" "sticky"
|
||||
, top (px 55)
|
||||
]
|
||||
, SideNav.collapsible
|
||||
{ isOpen = isSideNavOpen
|
||||
, toggle = ToggleSideNav
|
||||
, isTooltipOpen = openTooltip == Just SideNavOpenCloseTooltip
|
||||
, toggleTooltip = ToggleTooltip SideNavOpenCloseTooltip
|
||||
}
|
||||
, SideNav.navLabel "categories"
|
||||
, SideNav.navId "sidenav__categories"
|
||||
]
|
||||
(SideNav.entry "Usage Guidelines"
|
||||
[ SideNav.linkExternal "https://paper.dropbox.com/doc/UI-Style-Guide-and-Caveats--BhJHYronm1RGM1hRfnkvhrZMAg-PvOLxeX3oyujYEzdJx5pu"
|
||||
|
@ -26,7 +26,7 @@ import Example
|
||||
import Html.Styled exposing (..)
|
||||
import Html.Styled.Attributes exposing (css)
|
||||
import Nri.Ui.Fonts.V1 as Fonts
|
||||
import Nri.Ui.Heading.V2 as Heading
|
||||
import Nri.Ui.Heading.V3 as Heading
|
||||
import Nri.Ui.Html.V3 exposing (viewIf)
|
||||
import Nri.Ui.MediaQuery.V1 exposing (mobile)
|
||||
import Nri.Ui.Text.V6 as Text
|
||||
@ -89,9 +89,8 @@ viewExampleCode ellieLink component values =
|
||||
[ summary []
|
||||
[ Heading.h3
|
||||
[ Heading.css [ Css.display Css.inline ]
|
||||
, Heading.style Heading.Small
|
||||
, Heading.plaintext example.sectionName
|
||||
]
|
||||
[ text example.sectionName ]
|
||||
]
|
||||
, ellieLink
|
||||
{ fullModuleName = Example.fullName component
|
||||
@ -117,8 +116,9 @@ viewExampleCode ellieLink component values =
|
||||
|
||||
viewSection : String -> List Css.Style -> List (Html msg) -> Html msg
|
||||
viewSection name styles children =
|
||||
section [ css (flex (int 1) :: styles) ]
|
||||
(Heading.h2 [ Heading.style Heading.Subhead ] [ text name ]
|
||||
section
|
||||
[ css (flex (int 1) :: styles) ]
|
||||
(Heading.h2 [ Heading.plaintext name ]
|
||||
:: children
|
||||
)
|
||||
|
||||
|
@ -18,9 +18,9 @@ import Html.Styled.Attributes exposing (css, href)
|
||||
import Nri.Ui.BreadCrumbs.V1 as BreadCrumbs exposing (BreadCrumbs)
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.Fonts.V1 as Fonts
|
||||
import Nri.Ui.Heading.V2 as Heading
|
||||
import Nri.Ui.Heading.V3 as Heading
|
||||
import Nri.Ui.Svg.V1 as Svg exposing (Svg)
|
||||
import Nri.Ui.Table.V5 as Table
|
||||
import Nri.Ui.Table.V6 as Table
|
||||
import Nri.Ui.UiIcon.V1 as UiIcon
|
||||
|
||||
|
||||
@ -72,7 +72,7 @@ example =
|
||||
, toExampleCode = \settings -> [ { sectionName = moduleName ++ ".view", code = viewExampleCode settings } ]
|
||||
}
|
||||
, section [ css [ Css.margin2 (Css.px 20) Css.zero ] ]
|
||||
[ Heading.h2 [] [ text "Example" ]
|
||||
[ Heading.h2 [ Heading.plaintext "Example" ]
|
||||
, viewExample breadCrumbs
|
||||
]
|
||||
, Table.view
|
||||
@ -81,18 +81,21 @@ example =
|
||||
, value = .name
|
||||
, width = Css.pct 15
|
||||
, cellStyles = always []
|
||||
, sort = Nothing
|
||||
}
|
||||
, Table.string
|
||||
{ header = "About"
|
||||
, value = .about
|
||||
, width = Css.px 200
|
||||
, cellStyles = always []
|
||||
, sort = Nothing
|
||||
}
|
||||
, Table.string
|
||||
{ header = "Result"
|
||||
, value = \{ result } -> result breadCrumbs
|
||||
, width = Css.px 50
|
||||
, cellStyles = always []
|
||||
, sort = Nothing
|
||||
}
|
||||
]
|
||||
[ { name = "headerId"
|
||||
|
@ -18,7 +18,7 @@ import Example exposing (Example)
|
||||
import Html.Styled exposing (..)
|
||||
import Html.Styled.Attributes exposing (css)
|
||||
import Nri.Ui.Button.V10 as Button
|
||||
import Nri.Ui.Heading.V2 as Heading
|
||||
import Nri.Ui.Heading.V3 as Heading
|
||||
import Nri.Ui.UiIcon.V1 as UiIcon
|
||||
import Set exposing (Set)
|
||||
|
||||
@ -306,7 +306,7 @@ buttons model =
|
||||
toggleButtons : Set Int -> Html Msg
|
||||
toggleButtons pressedToggleButtons =
|
||||
div []
|
||||
[ Heading.h3 [] [ text "Button toggle" ]
|
||||
[ Heading.h3 [ Heading.plaintext "Button toggle" ]
|
||||
, div [ css [ Css.displayFlex, Css.marginBottom (Css.px 20) ] ]
|
||||
[ Button.toggleButton
|
||||
{ onDeselect = ToggleToggleButton 0
|
||||
|
@ -17,7 +17,7 @@ import Nri.Ui.Checkbox.V6 as Checkbox
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.Data.PremiumDisplay as PremiumDisplay
|
||||
import Nri.Ui.Fonts.V1 as Fonts
|
||||
import Nri.Ui.Heading.V2 as Heading
|
||||
import Nri.Ui.Heading.V3 as Heading
|
||||
import Nri.Ui.PremiumCheckbox.V8 as PremiumCheckbox
|
||||
import Nri.Ui.Svg.V1 as Svg
|
||||
import Set exposing (Set)
|
||||
@ -51,7 +51,7 @@ example =
|
||||
, viewLockedOnInsideCheckbox "styleguide-locked-on-inside-checkbox" state
|
||||
, viewDisabledCheckbox "styleguide-checkbox-disabled" state
|
||||
, viewMultilineCheckboxes state
|
||||
, Heading.h2 [ Heading.style Heading.Subhead ] [ text "Premium Checkboxes" ]
|
||||
, Heading.h2 [ Heading.plaintext "Premium Checkboxes" ]
|
||||
, viewPremiumCheckboxes state
|
||||
, viewCustomStyledCheckbox state
|
||||
, viewCustomStyledPremiumCheckboxes state
|
||||
@ -185,7 +185,7 @@ viewMultilineCheckboxes : State -> Html Msg
|
||||
viewMultilineCheckboxes state =
|
||||
Html.section
|
||||
[ css [ Css.width (Css.px 500) ] ]
|
||||
[ Heading.h2 [ Heading.style Heading.Subhead ] [ Html.text "Multiline Text in Checkboxes" ]
|
||||
[ Heading.h2 [ Heading.plaintext "Multiline Text in Checkboxes" ]
|
||||
, let
|
||||
id =
|
||||
"styleguide-checkbox-multiline"
|
||||
|
@ -187,6 +187,7 @@ viewExampleTable { label, icon, attributes } =
|
||||
[ ( "primary", ClickableSvg.primary )
|
||||
, ( "secondary", ClickableSvg.secondary )
|
||||
, ( "danger", ClickableSvg.danger )
|
||||
, ( "tertiary", ClickableSvg.tertiary )
|
||||
, ( "dangerSecondary", ClickableSvg.dangerSecondary )
|
||||
]
|
||||
, Html.tfoot []
|
||||
@ -295,4 +296,13 @@ initSettings =
|
||||
{ moduleName = "ClickableSvg"
|
||||
, use = ClickableSvg.notMobileCss
|
||||
}
|
||||
|> ControlExtra.optionalListItem "iconForMobile"
|
||||
(Control.map
|
||||
(\( name, icon ) ->
|
||||
( "ClickableSvg.iconForMobile " ++ name
|
||||
, ClickableSvg.iconForMobile icon
|
||||
)
|
||||
)
|
||||
CommonControls.uiIcon
|
||||
)
|
||||
)
|
||||
|
@ -14,7 +14,7 @@ import Html.Styled.Attributes as Attributes exposing (css)
|
||||
import Nri.Ui.Colors.Extra
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.Fonts.V1 as Fonts
|
||||
import Nri.Ui.Heading.V2 as Heading
|
||||
import Nri.Ui.Heading.V3 as Heading
|
||||
import Nri.Ui.Text.V6 as Text
|
||||
import SolidColor exposing (highContrast)
|
||||
|
||||
@ -91,7 +91,7 @@ example =
|
||||
, ( "sunshine", Colors.sunshine, "Yellow highlights, tips" )
|
||||
]
|
||||
|> viewColors
|
||||
, Heading.h2 [ Heading.style Heading.Subhead ] [ Html.text "Background Highlight Colors" ]
|
||||
, Heading.h2 [ Heading.plaintext "Background Highlight Colors" ]
|
||||
, Text.mediumBody [ Text.plaintext "Background highlights should be used as the default highlight style because they are more noticeable and readable. The dark colors should be used in the case where headings need to harmonize with highlighted containers, such as in Guided Drafts." ]
|
||||
, [ ( "highlightYellow", Colors.highlightYellow, "Yellow background highlights" )
|
||||
, ( "highlightYellowDark", Colors.highlightYellowDark, "Dark yellow background highlights" )
|
||||
@ -109,7 +109,7 @@ example =
|
||||
, ( "highlightBrownDark", Colors.highlightBrownDark, "Dark brown background highlights" )
|
||||
]
|
||||
|> viewColors
|
||||
, Heading.h2 [ Heading.style Heading.Subhead ] [ Html.text "Text Highlight Colors" ]
|
||||
, Heading.h2 [ Heading.plaintext "Text Highlight Colors" ]
|
||||
, Text.mediumBody [ Text.plaintext "Colors for highlighting text on a white background. These colors are readable at 14px bold and bigger." ]
|
||||
, [ ( "textHighlightYellow", Colors.textHighlightYellow, "Neutral text highlight #1" )
|
||||
, ( "textHighlightCyan", Colors.textHighlightCyan, "Neutral text highlight #2" )
|
||||
|
@ -16,7 +16,7 @@ import Example exposing (Example)
|
||||
import Html.Styled as Html exposing (Html)
|
||||
import Html.Styled.Attributes exposing (css)
|
||||
import Nri.Ui.Container.V2 as Container
|
||||
import Nri.Ui.Heading.V2 as Heading
|
||||
import Nri.Ui.Heading.V3 as Heading
|
||||
|
||||
|
||||
moduleName : String
|
||||
@ -119,7 +119,7 @@ viewExample { name, description } attributes =
|
||||
[ Css.marginTop (Css.px 20)
|
||||
]
|
||||
]
|
||||
[ Heading.h3 [] [ Html.text name ]
|
||||
[ Heading.h3 [ Heading.plaintext name ]
|
||||
, Html.text description
|
||||
, Container.view attributes
|
||||
]
|
||||
|
@ -12,7 +12,7 @@ import Example exposing (Example)
|
||||
import Html.Styled as Html exposing (Html)
|
||||
import Html.Styled.Attributes exposing (css)
|
||||
import Nri.Ui.Fonts.V1 as Fonts
|
||||
import Nri.Ui.Heading.V2 as Heading
|
||||
import Nri.Ui.Heading.V3 as Heading
|
||||
|
||||
|
||||
{-| -}
|
||||
@ -43,13 +43,13 @@ example =
|
||||
|> List.map viewPreview
|
||||
, view =
|
||||
\ellieLinkConfig _ ->
|
||||
[ Heading.h2 [ Heading.style Heading.Subhead ] [ Html.text "baseFont" ]
|
||||
[ Heading.h2 [ Heading.plaintext "baseFont" ]
|
||||
, Html.p [ css [ Fonts.baseFont ] ]
|
||||
[ Html.text "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz" ]
|
||||
, Heading.h2 [ Heading.style Heading.Subhead ] [ Html.text "quizFont" ]
|
||||
, Heading.h2 [ Heading.plaintext "quizFont" ]
|
||||
, Html.p [ css [ Fonts.quizFont ] ]
|
||||
[ Html.text "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz" ]
|
||||
, Heading.h2 [ Heading.style Heading.Subhead ] [ Html.text "ugFont" ]
|
||||
, Heading.h2 [ Heading.plaintext "ugFont" ]
|
||||
, Html.p [ css [ Fonts.ugFont ] ]
|
||||
[ Html.text "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz" ]
|
||||
]
|
||||
|
@ -12,8 +12,7 @@ import Debug.Control as Control exposing (Control)
|
||||
import Debug.Control.Extra as ControlExtra
|
||||
import Debug.Control.View as ControlView
|
||||
import Example exposing (Example)
|
||||
import Html.Styled as Html
|
||||
import Nri.Ui.Heading.V2 as Heading
|
||||
import Nri.Ui.Heading.V3 as Heading
|
||||
import ViewHelpers exposing (viewExamples)
|
||||
|
||||
|
||||
@ -24,7 +23,7 @@ moduleName =
|
||||
|
||||
version : Int
|
||||
version =
|
||||
2
|
||||
3
|
||||
|
||||
|
||||
{-| -}
|
||||
@ -38,20 +37,20 @@ example =
|
||||
, update = update
|
||||
, subscriptions = \_ -> Sub.none
|
||||
, preview =
|
||||
[ Heading.h1 [] [ Html.text "h1" ]
|
||||
, Heading.h2 [] [ Html.text "h2" ]
|
||||
, Heading.h3 [] [ Html.text "h3" ]
|
||||
, Heading.h4 [] [ Html.text "h4" ]
|
||||
[ Heading.h1 [ Heading.plaintext "h1" ]
|
||||
, Heading.h2 [ Heading.plaintext "h2" ]
|
||||
, Heading.h3 [ Heading.plaintext "h3" ]
|
||||
, Heading.h4 [ Heading.plaintext "h4" ]
|
||||
]
|
||||
, view =
|
||||
\ellieLinkConfig state ->
|
||||
let
|
||||
examples =
|
||||
[ ( "h1", Heading.h1, "This is the main page heading." )
|
||||
, ( "h2", Heading.h2, "This is a tagline" )
|
||||
, ( "h3", Heading.h3, "This is a subHeading" )
|
||||
, ( "h4", Heading.h4, "This is a smallHeading" )
|
||||
, ( "h5", Heading.h5, "This is also a smallHeading" )
|
||||
[ ( "h1", Heading.h1 )
|
||||
, ( "h2", Heading.h2 )
|
||||
, ( "h3", Heading.h3 )
|
||||
, ( "h4", Heading.h4 )
|
||||
, ( "h5", Heading.h5 )
|
||||
]
|
||||
|
||||
attributes =
|
||||
@ -68,7 +67,7 @@ example =
|
||||
, toExampleCode =
|
||||
\settings ->
|
||||
let
|
||||
toExampleCode ( name, _, content ) =
|
||||
toExampleCode ( name, _ ) =
|
||||
{ sectionName = name
|
||||
, code =
|
||||
moduleName
|
||||
@ -77,16 +76,12 @@ example =
|
||||
++ "\n [ "
|
||||
++ String.join "\n , " (List.map Tuple.first settings)
|
||||
++ "\n ]"
|
||||
++ ("\n [ Html.text \"" ++ content ++ "\" ]")
|
||||
}
|
||||
in
|
||||
List.map toExampleCode examples
|
||||
}
|
||||
, examples
|
||||
|> List.map
|
||||
(\( name, view, content ) ->
|
||||
( name, view attributes [ Html.text content ] )
|
||||
)
|
||||
|> List.map (\( name, view ) -> ( name, view attributes ))
|
||||
|> viewExamples
|
||||
]
|
||||
}
|
||||
@ -102,29 +97,30 @@ init : State
|
||||
init =
|
||||
{ control =
|
||||
ControlExtra.list
|
||||
|> ControlExtra.listItem "content" controlContent
|
||||
|> CommonControls.css { moduleName = moduleName, use = Heading.css }
|
||||
|> ControlExtra.optionalBoolListItem "error" ( "Heading.error", Heading.error )
|
||||
|> ControlExtra.optionalListItem "style" controlStyle
|
||||
}
|
||||
|
||||
|
||||
controlContent : Control ( String, Heading.Attribute msg )
|
||||
controlContent =
|
||||
CommonControls.content
|
||||
{ moduleName = moduleName
|
||||
, plaintext = Heading.plaintext
|
||||
, markdown = Just Heading.markdown
|
||||
, html = Heading.html
|
||||
, httpError = Nothing
|
||||
}
|
||||
|
||||
|
||||
controlStyle : Control ( String, Heading.Attribute msg )
|
||||
controlStyle =
|
||||
[ ( "Top", Heading.Top )
|
||||
, ( "Tagline", Heading.Tagline )
|
||||
, ( "Subhead", Heading.Subhead )
|
||||
, ( "Small", Heading.Small )
|
||||
]
|
||||
|> List.map
|
||||
(\( name, val ) ->
|
||||
( name
|
||||
, Control.value
|
||||
( "Heading.style Heading." ++ name
|
||||
, Heading.style val
|
||||
)
|
||||
)
|
||||
)
|
||||
|> Control.choice
|
||||
CommonControls.choice moduleName
|
||||
[ ( "top", Heading.top )
|
||||
, ( "subhead", Heading.subhead )
|
||||
, ( "small", Heading.small )
|
||||
]
|
||||
|
||||
|
||||
type alias Settings =
|
||||
|
@ -24,7 +24,7 @@ import Html.Styled.Events as Events
|
||||
import Nri.Ui.Checkbox.V6 as Checkbox
|
||||
import Nri.Ui.Colors.Extra exposing (fromCssColor, toCssColor)
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.Heading.V2 as Heading
|
||||
import Nri.Ui.Heading.V3 as Heading
|
||||
import Nri.Ui.Select.V8 as Select
|
||||
import Nri.Ui.Svg.V1 as Svg exposing (Svg)
|
||||
import Nri.Ui.Text.V6 as Text
|
||||
@ -189,7 +189,7 @@ view settings groups =
|
||||
viewSettings settings
|
||||
:: List.map viewExampleSection groups
|
||||
++ [ Html.section [ css [ Css.margin2 (Css.px 30) Css.zero ] ]
|
||||
[ Heading.h3 [] [ Html.text "Example Usage" ]
|
||||
[ Heading.h3 [ Heading.plaintext "Example Usage" ]
|
||||
, viewSingularExampleSettings groups settings
|
||||
, viewResults settings
|
||||
]
|
||||
@ -214,8 +214,8 @@ viewWithCustomStyles { showIconName } headerText icons =
|
||||
, Css.lineHeight (Css.num 1.2)
|
||||
, Css.fontWeight (Css.int 700)
|
||||
]
|
||||
, Heading.plaintext headerText
|
||||
]
|
||||
[ Html.text headerText ]
|
||||
, Html.div
|
||||
[ css
|
||||
[ Css.displayFlex
|
||||
|
@ -58,6 +58,13 @@ all =
|
||||
, Css.margin (Css.px 4)
|
||||
]
|
||||
)
|
||||
, ( "noredinkMonochrome"
|
||||
, Logo.noredinkMonochrome
|
||||
, [ Css.height (Css.px 25)
|
||||
, Css.width (Css.px 100)
|
||||
, Css.margin (Css.px 4)
|
||||
]
|
||||
)
|
||||
]
|
||||
)
|
||||
, ( "Social Media"
|
||||
|
@ -9,7 +9,7 @@ import Debug.Control.Extra as ControlExtra
|
||||
import Debug.Control.View as ControlView
|
||||
import Example exposing (Example)
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.Heading.V2 as Heading
|
||||
import Nri.Ui.Heading.V3 as Heading
|
||||
import Nri.Ui.Message.V3 as Message
|
||||
import ViewHelpers exposing (viewExamples)
|
||||
|
||||
@ -194,8 +194,8 @@ example =
|
||||
, Css.borderTop3 (Css.px 2) Css.solid Colors.gray96
|
||||
, Css.paddingTop (Css.px 20)
|
||||
]
|
||||
, Heading.plaintext "Message.somethingWentWrong"
|
||||
]
|
||||
[ text "Message.somethingWentWrong" ]
|
||||
, Message.somethingWentWrong exampleRailsError
|
||||
]
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ import Html.Styled as Html exposing (Html)
|
||||
import Html.Styled.Attributes exposing (css)
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.Fonts.V1 as Fonts
|
||||
import Nri.Ui.Heading.V2 as Heading
|
||||
import Nri.Ui.Heading.V3 as Heading
|
||||
import Nri.Ui.Page.V3 as Page exposing (DefaultPage, RecoveryText(..))
|
||||
|
||||
|
||||
@ -113,7 +113,7 @@ example =
|
||||
}
|
||||
]
|
||||
}
|
||||
, Heading.h2 [ Heading.style Heading.Subhead ] [ Html.text "Example" ]
|
||||
, Heading.h2 [ Heading.plaintext "Example" ]
|
||||
, Tuple.second settings.page
|
||||
{ link = ShowItWorked
|
||||
, recoveryText = settings.recoveryText
|
||||
|
@ -20,13 +20,13 @@ import Debug.Control.Extra as ControlExtra
|
||||
import Debug.Control.View as ControlView
|
||||
import EllieLink
|
||||
import Example exposing (Example)
|
||||
import Html.Styled as Html exposing (..)
|
||||
import Html.Styled exposing (..)
|
||||
import Html.Styled.Attributes exposing (css)
|
||||
import KeyboardSupport exposing (Direction(..), Key(..))
|
||||
import Nri.Ui.Button.V10 as Button
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.Data.PremiumDisplay as PremiumDisplay
|
||||
import Nri.Ui.Heading.V2 as Heading
|
||||
import Nri.Ui.Heading.V3 as Heading
|
||||
import Nri.Ui.Modal.V11 as Modal
|
||||
import Nri.Ui.RadioButton.V4 as RadioButton
|
||||
import Nri.Ui.Text.V6 as Text
|
||||
@ -125,7 +125,7 @@ view ellieLinkConfig state =
|
||||
}
|
||||
]
|
||||
}
|
||||
, Heading.h2 [ Heading.style Heading.Subhead ] [ Html.text "Example" ]
|
||||
, Heading.h2 [ Heading.plaintext "Example" ]
|
||||
, viewExamples selectionSettings state.selectedValue
|
||||
, Modal.view
|
||||
{ title = "Go Premium!"
|
||||
|
@ -15,7 +15,7 @@ import Debug.Control.View as ControlView
|
||||
import Example exposing (Example)
|
||||
import Html.Styled
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.Heading.V2 as Heading
|
||||
import Nri.Ui.Heading.V3 as Heading
|
||||
import Nri.Ui.Select.V8 as Select exposing (Choice)
|
||||
|
||||
|
||||
@ -77,7 +77,7 @@ example =
|
||||
}
|
||||
]
|
||||
}
|
||||
, Heading.h2 [ Heading.style Heading.Subhead ] [ Html.Styled.text "Example" ]
|
||||
, Heading.h2 [ Heading.plaintext "Example" ]
|
||||
, Select.view label attributes
|
||||
|> Html.Styled.map ConsoleLog
|
||||
]
|
||||
|
@ -17,12 +17,12 @@ import EllieLink
|
||||
import Example exposing (Example)
|
||||
import Html.Styled.Attributes exposing (css)
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.SideNav.V3 as SideNav
|
||||
import Nri.Ui.SideNav.V4 as SideNav
|
||||
|
||||
|
||||
version : Int
|
||||
version =
|
||||
3
|
||||
4
|
||||
|
||||
|
||||
{-| -}
|
||||
@ -124,7 +124,7 @@ type alias State =
|
||||
|
||||
type alias Settings =
|
||||
{ currentRoute : String
|
||||
, navAttributes : List ( String, SideNav.NavAttribute )
|
||||
, navAttributes : List ( String, SideNav.NavAttribute Msg )
|
||||
, entries : List ( String, SideNav.Entry String Msg )
|
||||
}
|
||||
|
||||
@ -140,7 +140,7 @@ init =
|
||||
}
|
||||
|
||||
|
||||
controlNavAttributes : Control (List ( String, SideNav.NavAttribute ))
|
||||
controlNavAttributes : Control (List ( String, SideNav.NavAttribute Msg ))
|
||||
controlNavAttributes =
|
||||
ControlExtra.list
|
||||
|> ControlExtra.optionalListItemDefaultChecked "navLabel"
|
||||
|
@ -13,10 +13,10 @@ import Html.Styled as Html exposing (..)
|
||||
import Html.Styled.Attributes exposing (css)
|
||||
import Nri.Ui.Button.V10 as Button
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.Heading.V2 as Heading
|
||||
import Nri.Ui.Heading.V3 as Heading
|
||||
import Nri.Ui.SortableTable.V3 as SortableTable
|
||||
import Nri.Ui.Svg.V1 as Svg exposing (Svg)
|
||||
import Nri.Ui.Table.V5 as Table
|
||||
import Nri.Ui.Table.V6 as Table
|
||||
import Nri.Ui.UiIcon.V1 as UiIcon
|
||||
|
||||
|
||||
@ -84,12 +84,14 @@ example =
|
||||
, view = .x >> Html.text
|
||||
, width = px 50
|
||||
, cellStyles = always []
|
||||
, sort = Nothing
|
||||
}
|
||||
, Table.custom
|
||||
{ header = header "Y"
|
||||
, view = .y >> Html.text
|
||||
, width = px 50
|
||||
, cellStyles = always []
|
||||
, sort = Nothing
|
||||
}
|
||||
]
|
||||
[ { x = "Row 1 X"
|
||||
@ -152,9 +154,9 @@ example =
|
||||
, { firstName = "First5", lastName = "Last5", coins = 5 }
|
||||
]
|
||||
in
|
||||
[ Heading.h2 [ Heading.style Heading.Subhead ] [ Html.text "With sortable headers" ]
|
||||
[ Heading.h2 [ Heading.plaintext "With sortable headers" ]
|
||||
, SortableTable.view config sortState data
|
||||
, Heading.h2 [ Heading.style Heading.Subhead ] [ Html.text "Loading" ]
|
||||
, Heading.h2 [ Heading.plaintext "Loading" ]
|
||||
, SortableTable.viewLoading config sortState
|
||||
]
|
||||
}
|
||||
|
@ -13,8 +13,8 @@ import Debug.Control as Control exposing (Control)
|
||||
import Debug.Control.View as ControlView
|
||||
import Example exposing (Example)
|
||||
import Nri.Ui.Button.V10 as Button
|
||||
import Nri.Ui.Heading.V2 as Heading
|
||||
import Nri.Ui.Table.V5 as Table exposing (Column)
|
||||
import Nri.Ui.Heading.V3 as Heading
|
||||
import Nri.Ui.Table.V6 as Table exposing (Column)
|
||||
|
||||
|
||||
{-| -}
|
||||
@ -49,12 +49,14 @@ example =
|
||||
, value = .a
|
||||
, width = Css.px 50
|
||||
, cellStyles = always []
|
||||
, sort = Nothing
|
||||
}
|
||||
, Table.string
|
||||
{ header = "B"
|
||||
, value = .b
|
||||
, width = Css.px 50
|
||||
, cellStyles = always []
|
||||
, sort = Nothing
|
||||
}
|
||||
]
|
||||
[ { a = "Row 1 A"
|
||||
@ -104,7 +106,7 @@ example =
|
||||
, toExampleCode "viewLoadingWithoutHeader" ""
|
||||
]
|
||||
}
|
||||
, Heading.h2 [ Heading.style Heading.Subhead ] [ text "Example" ]
|
||||
, Heading.h2 [ Heading.plaintext "Example" ]
|
||||
, case ( showHeader, isLoading ) of
|
||||
( True, False ) ->
|
||||
Table.view columns data
|
||||
@ -187,6 +189,7 @@ columnsWithCode =
|
||||
, " , value = .firstName"
|
||||
, " , width = Css.calc (Css.pct 50) Css.minus (Css.px 250)"
|
||||
, " , cellStyles = always []"
|
||||
, " , sort = Nothing"
|
||||
, " }"
|
||||
]
|
||||
|> String.join "\n\t "
|
||||
@ -195,6 +198,7 @@ columnsWithCode =
|
||||
, value = .firstName
|
||||
, width = Css.calc (Css.pct 50) Css.minus (Css.px 250)
|
||||
, cellStyles = always []
|
||||
, sort = Nothing
|
||||
}
|
||||
)
|
||||
, ( [ "Table.string"
|
||||
@ -202,6 +206,7 @@ columnsWithCode =
|
||||
, " , value = .lastName"
|
||||
, " , width = Css.calc (Css.pct 50) Css.minus (Css.px 250)"
|
||||
, " , cellStyles = always []"
|
||||
, " , sort = Nothing"
|
||||
, " }"
|
||||
]
|
||||
|> String.join "\n\t "
|
||||
@ -210,6 +215,7 @@ columnsWithCode =
|
||||
, value = .lastName
|
||||
, width = Css.calc (Css.pct 50) Css.minus (Css.px 250)
|
||||
, cellStyles = always []
|
||||
, sort = Nothing
|
||||
}
|
||||
)
|
||||
, ( [ "Table.string"
|
||||
@ -217,6 +223,7 @@ columnsWithCode =
|
||||
, " , value = .submitted >> String.fromInt"
|
||||
, " , width = Css.px 125"
|
||||
, " , cellStyles = always [ Css.textAlign Css.center ]"
|
||||
, " , sort = Nothing"
|
||||
, " }"
|
||||
]
|
||||
|> String.join "\n\t "
|
||||
@ -225,6 +232,7 @@ columnsWithCode =
|
||||
, value = .submitted >> String.fromInt
|
||||
, width = Css.px 125
|
||||
, cellStyles = \value -> [ Css.textAlign Css.center ]
|
||||
, sort = Nothing
|
||||
}
|
||||
)
|
||||
, ( [ "Table.custom"
|
||||
@ -232,6 +240,7 @@ columnsWithCode =
|
||||
, " , width = Css.px 250"
|
||||
, " , view = \\_ -> Button.button \"Action\" [ Button.small ]"
|
||||
, " , cellStyles = always []"
|
||||
, " , sort = Nothing"
|
||||
, " }"
|
||||
]
|
||||
|> String.join "\n\t "
|
||||
@ -240,6 +249,7 @@ columnsWithCode =
|
||||
, width = Css.px 250
|
||||
, view = \_ -> Button.button "Action" [ Button.small, Button.onClick (ConsoleLog "Clicked button!") ]
|
||||
, cellStyles = always []
|
||||
, sort = Nothing
|
||||
}
|
||||
)
|
||||
]
|
||||
|
@ -15,7 +15,7 @@ import Debug.Control.View as ControlView
|
||||
import Example exposing (Example)
|
||||
import Html.Styled as Html exposing (Html)
|
||||
import Html.Styled.Attributes exposing (css)
|
||||
import Nri.Ui.Heading.V2 as Heading
|
||||
import Nri.Ui.Heading.V3 as Heading
|
||||
import Nri.Ui.Text.V6 as Text
|
||||
|
||||
|
||||
@ -82,8 +82,8 @@ example =
|
||||
, toExampleCode "ugSmallBody"
|
||||
]
|
||||
}
|
||||
, Heading.h2 [] [ Html.text "Examples" ]
|
||||
, Heading.h3 [] [ Html.text "Paragraph styles" ]
|
||||
, Heading.h2 [ Heading.plaintext "Examples" ]
|
||||
, Heading.h3 [ Heading.plaintext "Paragraph styles" ]
|
||||
, viewExamples
|
||||
[ ( "mediumBody", Text.mediumBody )
|
||||
, ( "smallBody", Text.smallBody )
|
||||
@ -91,7 +91,7 @@ example =
|
||||
, ( "caption", Text.caption )
|
||||
]
|
||||
attributes
|
||||
, Heading.h3 [] [ Html.text "Paragraph styles for user-authored content" ]
|
||||
, Heading.h3 [ Heading.plaintext "Paragraph styles for user-authored content" ]
|
||||
, viewExamples
|
||||
[ ( "ugMediumBody", Text.ugMediumBody )
|
||||
, ( "ugSmallBody", Text.ugSmallBody )
|
||||
|
@ -14,7 +14,7 @@ import Html.Styled as Html
|
||||
import Html.Styled.Attributes as Attributes exposing (css)
|
||||
import Nri.Ui.Checkbox.V6 as Checkbox
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.Heading.V2 as Heading
|
||||
import Nri.Ui.Heading.V3 as Heading
|
||||
import Nri.Ui.InputStyles.V3 as InputStyles exposing (Theme(..))
|
||||
import Nri.Ui.TextArea.V4 as TextArea
|
||||
|
||||
@ -71,7 +71,7 @@ example =
|
||||
]
|
||||
, view =
|
||||
\ellieLinkConfig state ->
|
||||
[ Heading.h1 [] [ Html.text "Textarea controls" ]
|
||||
[ Heading.h1 [ Heading.plaintext "Textarea controls" ]
|
||||
, Html.div []
|
||||
[ Checkbox.viewWithLabel
|
||||
{ identifier = "show-textarea-label"
|
||||
|
@ -6,7 +6,7 @@ module Examples.TextInput exposing (Msg, State, example)
|
||||
|
||||
-}
|
||||
|
||||
import Accessibility.Styled as Html exposing (..)
|
||||
import Accessibility.Styled exposing (..)
|
||||
import Accessibility.Styled.Key as Key
|
||||
import Category exposing (Category(..))
|
||||
import Css
|
||||
@ -16,7 +16,7 @@ import Debug.Control.View as ControlView
|
||||
import Dict exposing (Dict)
|
||||
import Example exposing (Example)
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.Heading.V2 as Heading
|
||||
import Nri.Ui.Heading.V3 as Heading
|
||||
import Nri.Ui.TextInput.V7 as TextInput
|
||||
import ViewHelpers exposing (viewExamples)
|
||||
|
||||
@ -62,7 +62,7 @@ example =
|
||||
, extraImports = []
|
||||
, toExampleCode = \_ -> []
|
||||
}
|
||||
, Heading.h2 [ Heading.style Heading.Subhead ] [ Html.text "Example" ]
|
||||
, Heading.h2 [ Heading.plaintext "Example" ]
|
||||
, viewExamples <|
|
||||
( "readOnlyText"
|
||||
, TextInput.view "Shareable Assignment Link"
|
||||
@ -165,6 +165,78 @@ customizableExamples state =
|
||||
, onBlur = "Blurred!!!"
|
||||
, onEnter = "Entered!!!"
|
||||
}
|
||||
, toExample
|
||||
{ name = "givenName"
|
||||
, toString = identity
|
||||
, inputType = TextInput.givenName
|
||||
, onFocus = "Focused!!!"
|
||||
, onBlur = "Blurred!!!"
|
||||
, onEnter = "Entered!!!"
|
||||
}
|
||||
, toExample
|
||||
{ name = "familyName"
|
||||
, toString = identity
|
||||
, inputType = TextInput.familyName
|
||||
, onFocus = "Focused!!!"
|
||||
, onBlur = "Blurred!!!"
|
||||
, onEnter = "Entered!!!"
|
||||
}
|
||||
, toExample
|
||||
{ name = "organization"
|
||||
, toString = identity
|
||||
, inputType = TextInput.organization
|
||||
, onFocus = "Focused!!!"
|
||||
, onBlur = "Blurred!!!"
|
||||
, onEnter = "Entered!!!"
|
||||
}
|
||||
, toExample
|
||||
{ name = "organizationTitle"
|
||||
, toString = identity
|
||||
, inputType = TextInput.organizationTitle
|
||||
, onFocus = "Focused!!!"
|
||||
, onBlur = "Blurred!!!"
|
||||
, onEnter = "Entered!!!"
|
||||
}
|
||||
, toExample
|
||||
{ name = "addressLine1"
|
||||
, toString = identity
|
||||
, inputType = TextInput.addressLine1
|
||||
, onFocus = "Focused!!!"
|
||||
, onBlur = "Blurred!!!"
|
||||
, onEnter = "Entered!!!"
|
||||
}
|
||||
, toExample
|
||||
{ name = "addressLevel2"
|
||||
, toString = identity
|
||||
, inputType = TextInput.addressLevel2
|
||||
, onFocus = "Focused!!!"
|
||||
, onBlur = "Blurred!!!"
|
||||
, onEnter = "Entered!!!"
|
||||
}
|
||||
, toExample
|
||||
{ name = "postalCode"
|
||||
, toString = identity
|
||||
, inputType = TextInput.postalCode
|
||||
, onFocus = "Focused!!!"
|
||||
, onBlur = "Blurred!!!"
|
||||
, onEnter = "Entered!!!"
|
||||
}
|
||||
, toExample
|
||||
{ name = "tel"
|
||||
, toString = identity
|
||||
, inputType = TextInput.tel
|
||||
, onFocus = "Focused!!!"
|
||||
, onBlur = "Blurred!!!"
|
||||
, onEnter = "Entered!!!"
|
||||
}
|
||||
, toExample
|
||||
{ name = "sex"
|
||||
, toString = identity
|
||||
, inputType = TextInput.sex
|
||||
, onFocus = "Focused!!!"
|
||||
, onBlur = "Blurred!!!"
|
||||
, onEnter = "Entered!!!"
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
|
@ -22,9 +22,9 @@ import Markdown
|
||||
import Nri.Ui.ClickableSvg.V2 as ClickableSvg
|
||||
import Nri.Ui.ClickableText.V3 as ClickableText
|
||||
import Nri.Ui.Colors.V1 as Colors
|
||||
import Nri.Ui.Heading.V2 as Heading
|
||||
import Nri.Ui.Heading.V3 as Heading
|
||||
import Nri.Ui.Svg.V1 as Svg
|
||||
import Nri.Ui.Table.V5 as Table
|
||||
import Nri.Ui.Table.V6 as Table
|
||||
import Nri.Ui.Tooltip.V3 as Tooltip
|
||||
import Nri.Ui.UiIcon.V1 as UiIcon
|
||||
|
||||
@ -134,31 +134,35 @@ update msg model =
|
||||
view : EllieLink.Config -> State -> List (Html Msg)
|
||||
view ellieLinkConfig model =
|
||||
[ viewCustomizableExample ellieLinkConfig model.staticExampleSettings
|
||||
, Heading.h2 [ Heading.style Heading.Subhead ] [ Html.text "What type of tooltip should I use?" ]
|
||||
, Heading.h2 [ Heading.plaintext "What type of tooltip should I use?" ]
|
||||
, Table.view
|
||||
[ Table.string
|
||||
{ header = "Type"
|
||||
, value = .name
|
||||
, width = Css.pct 15
|
||||
, cellStyles = always [ Css.padding2 (Css.px 14) (Css.px 7), Css.verticalAlign Css.top, Css.fontWeight Css.bold ]
|
||||
, sort = Nothing
|
||||
}
|
||||
, Table.custom
|
||||
{ header = Html.text "Usage"
|
||||
, view = .usage >> Markdown.toHtml Nothing >> List.map Html.fromUnstyled >> Html.span []
|
||||
, width = Css.px 150
|
||||
, cellStyles = always [ Css.padding2 Css.zero (Css.px 7), Css.verticalAlign Css.top ]
|
||||
, sort = Nothing
|
||||
}
|
||||
, Table.custom
|
||||
{ header = Html.text "About"
|
||||
, view = .description >> Markdown.toHtml Nothing >> List.map Html.fromUnstyled >> Html.span []
|
||||
, width = Css.px 200
|
||||
, cellStyles = always [ Css.padding2 Css.zero (Css.px 7), Css.verticalAlign Css.top ]
|
||||
, sort = Nothing
|
||||
}
|
||||
, Table.custom
|
||||
{ header = Html.text "Example"
|
||||
, view = .example
|
||||
, width = Css.px 50
|
||||
, cellStyles = always [ Css.textAlign Css.center ]
|
||||
, sort = Nothing
|
||||
}
|
||||
]
|
||||
[ { name = "Tooltip.primaryLabel"
|
||||
|
@ -58,6 +58,7 @@ all =
|
||||
, ( "download", UiIcon.download, [] )
|
||||
, ( "sort", UiIcon.sort, [] )
|
||||
, ( "gear", UiIcon.gear, [] )
|
||||
, ( "hamburger", UiIcon.hamburger, [] )
|
||||
]
|
||||
)
|
||||
, ( "Archive & Unarchive"
|
||||
@ -89,6 +90,7 @@ all =
|
||||
, ( "Guidance"
|
||||
, [ ( "footsteps", UiIcon.footsteps, [] )
|
||||
, ( "help", UiIcon.help, [] )
|
||||
, ( "info", UiIcon.info, [] )
|
||||
, ( "checklist", UiIcon.checklist, [] )
|
||||
, ( "checklistComplete", UiIcon.checklistComplete, [] )
|
||||
]
|
||||
@ -184,6 +186,7 @@ all =
|
||||
, ( "Badges & Celebration"
|
||||
, [ ( "badge", UiIcon.badge, [] )
|
||||
, ( "tada", UiIcon.tada, [] )
|
||||
, ( "count", UiIcon.count, [] )
|
||||
]
|
||||
)
|
||||
, ( "Lock & Key"
|
||||
|
@ -27,6 +27,7 @@
|
||||
"Nri.Ui.FocusTrap.V1",
|
||||
"Nri.Ui.Fonts.V1",
|
||||
"Nri.Ui.Heading.V2",
|
||||
"Nri.Ui.Heading.V3",
|
||||
"Nri.Ui.Html.Attributes.V2",
|
||||
"Nri.Ui.Html.V3",
|
||||
"Nri.Ui.InputStyles.V3",
|
||||
@ -47,12 +48,14 @@
|
||||
"Nri.Ui.Select.V8",
|
||||
"Nri.Ui.Shadows.V1",
|
||||
"Nri.Ui.SideNav.V3",
|
||||
"Nri.Ui.SideNav.V4",
|
||||
"Nri.Ui.SortableTable.V2",
|
||||
"Nri.Ui.SortableTable.V3",
|
||||
"Nri.Ui.Sprite.V1",
|
||||
"Nri.Ui.Svg.V1",
|
||||
"Nri.Ui.Switch.V2",
|
||||
"Nri.Ui.Table.V5",
|
||||
"Nri.Ui.Table.V6",
|
||||
"Nri.Ui.Tabs.V6",
|
||||
"Nri.Ui.Tabs.V7",
|
||||
"Nri.Ui.Text.V6",
|
||||
|
Loading…
Reference in New Issue
Block a user