Skip to content

Commit

Permalink
feat: new select component (#6)
Browse files Browse the repository at this point in the history
  • Loading branch information
MAHcodes authored Sep 22, 2024
1 parent e0dfbf5 commit f51a41d
Show file tree
Hide file tree
Showing 8 changed files with 370 additions and 14 deletions.
129 changes: 129 additions & 0 deletions app/src/components/ui/select.gleam
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import gleam/string
import lustre/attribute.{type Attribute, class}
import lustre/element.{type Element}
import lustre/element/html.{div, label}

pub type Colors {
Neutral
Primary
Secondary
Success
Info
Warning
Danger
}

pub fn select(
attributes: List(Attribute(a)),
children: List(Element(a)),
) -> Element(a) {
label([class("relative")], [
html.select(
[
class(
"appearance-none enabled:cursor-pointer disabled:opacity-50 [&:disabled+div]:opacity-50 disabled:cursor-not-allowed w-full",
),
..attributes
],
children,
),
div(
[
class(
[
"pointer-events-none",
"before:absolute before:size-1 before:right-4 before:pointer-events-none",
"before:border-4 before:border-x-transparent before:border-t-0 before:border-b-current before:top-1/2 before:-translate-y-[133.333333%]",
"after:absolute after:size-1 after:right-4 after:pointer-events-none",
"after:border-4 after:border-x-transparent after:border-b-0 after:border-t-current after:top-1/2 after:translate-y-1/3",
]
|> string.join(" "),
),
],
[],
),
])
}

pub fn flat(color: Colors) -> Attribute(a) {
case color {
Neutral ->
"text-neutral bg-neutral/20 hover:enabled:bg-neutral/30 [&+div]:text-neutral"
Primary ->
"text-primary bg-primary/20 hover:enabled:bg-primary/30 [&+div]:text-primary"
Secondary ->
"text-secondary bg-secondary/20 hover:enabled:bg-secondary/30 [&+div]:text-secondary"
Success ->
"text-success bg-success/20 hover:enabled:bg-success/30 [&+div]:text-success"
Info -> "text-info bg-info/20 hover:enabled:bg-info/30 [&+div]:text-info"
Warning ->
"text-warning bg-warning/20 hover:enabled:bg-warning/30 [&+div]:text-warning"
Danger ->
"text-danger bg-danger/20 hover:enabled:bg-danger/30 [&+div]:text-danger"
}
|> string.append(
" focus:outline-none focus:ring-2 focus:ring-current open:outline-none open:ring-2 open:ring-current",
)
|> class
}

pub fn outlined(color: Colors) -> Attribute(a) {
case color {
Neutral ->
"border-neutral focus:enabled:border-neutral open:enabled:border-neutral hover:enabled:border-neutral text-neutral [&+div]:text-neutral"
Primary ->
"border-primary focus:enabled:border-primary open:enabled:border-primary hover:enabled:border-primary text-primary [&+div]:text-primary"
Secondary ->
"border-secondary focus:enabled:border-secondary open:enabled:border-secondary hover:enabled:border-secondary text-secondary [&+div]:text-secondary"
Success ->
"border-success focus:enabled:border-success open:enabled:border-success hover:enabled:border-success text-success [&+div]:text-success"
Info ->
"border-info focus:enabled:border-info open:enabled:border-info hover:enabled:border-info text-info [&+div]:text-info"
Warning ->
"border-warning focus:enabled:border-warning open:enabled:border-warning hover:enabled:border-warning text-warning [&+div]:text-warning"
Danger ->
"border-danger focus:enabled:border-danger open:enabled:border-danger hover:enabled:border-danger text-danger [&+div]:text-danger"
}
|> string.append(
[
" bg-transparent border-2 border-opacity-50 placeholder-opacity-70",
"hover:enabled:border-opacity-100 focus:enabled:border-opacity-100 open:enabled:border-opacity-100",
"focus:outline-none focus:ring-2 focus:ring-current",
"open:outline-none open:ring-2 open:ring-current",
]
|> string.join(" "),
)
|> class
}

pub fn underlined(color: Colors) -> Attribute(a) {
case color {
Neutral -> "border-neutral text-neutral [&+div]:text-neutral"
Primary -> "border-primary text-primary [&+div]:text-primary"
Secondary -> "border-secondary text-secondary [&+div]:text-secondary"
Success -> "border-success text-success [&+div]:text-success"
Info -> "border-info text-info [&+div]:text-info"
Warning -> "border-warning text-warning [&+div]:text-warning"
Danger -> "border-danger text-danger [&+div]:text-danger"
}
|> string.append(
[
" bg-transparent border-opacity-20 border-b-2 outline-none rounded-b-none",
"focus:enabled:border-opacity-100 open:enabled:border-opacity-100",
]
|> string.join(" "),
)
|> class
}

pub fn sm() -> Attribute(a) {
class("rounded-sm pl-3.5 pr-9 py-1.5 text-sm")
}

pub fn md() -> Attribute(a) {
class("rounded-md pl-4 pr-10 py-2 text-base")
}

pub fn lg() -> Attribute(a) {
class("rounded-lg pl-5 pr-12 py-2.5 text-lg")
}
2 changes: 2 additions & 0 deletions app/src/gleez_ui.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ fn on_url_change(uri: Uri) -> Msg {
["docs", "components", "spinner"] -> OnRouteChange(route.Spinner)
["docs", "components", "skeleton"] -> OnRouteChange(route.Skeleton)
["docs", "components", "slider"] -> OnRouteChange(route.Slider)
["docs", "components", "select"] -> OnRouteChange(route.Select)
_ -> OnRouteChange(route.Home)
}
}
Expand Down Expand Up @@ -144,6 +145,7 @@ fn with_aside(model: Model) -> Element(Msg) {
route.Spinner -> page.spinner()
route.Skeleton -> page.skeleton()
route.Slider -> page.slider()
route.Select -> page.select()
_ -> page.home()
},
]),
Expand Down
17 changes: 11 additions & 6 deletions app/src/model/route.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ pub type Pages {
Spinner
Skeleton
Slider
Select
}

pub const home = "/"
Expand Down Expand Up @@ -74,6 +75,8 @@ pub const skeleton = "/docs/components/skeleton/"

pub const slider = "/docs/components/slider/"

pub const select = "/docs/components/select/"

pub type Status {
None
New
Expand Down Expand Up @@ -102,17 +105,17 @@ pub fn pages() -> List(Page) {
Page(input, [], None),
Page(link, [], None),
Page(chip, [], None),
Page(divider, [], Updated),
Page(divider, [], None),
Page(tooltip, [], None),
Page(avatar, [], None),
Page(badge, [], None),
Page(breadcrumbs, [], None),
Page(switch, [], None),
Page(kbd, [], New),
Page(checkbox, [], New),
Page(spinner, [], New),
Page(skeleton, [], New),
Page(slider, [], New),
Page(kbd, [], None),
Page(checkbox, [], None),
Page(spinner, [], None),
Page(skeleton, [], None),
Page(select, [], New),
]
|> sort_pages,
None,
Expand Down Expand Up @@ -144,6 +147,7 @@ pub fn to_path(page: Pages) -> String {
Spinner -> spinner
Skeleton -> skeleton
Slider -> slider
Select -> select
}
}

Expand All @@ -170,6 +174,7 @@ pub fn to_pages(uri: Uri) -> Pages {
p if p == spinner -> Spinner
p if p == skeleton -> Skeleton
p if p == slider -> Slider
p if p == select -> Select
_ -> Home
}
}
Expand Down
16 changes: 10 additions & 6 deletions app/src/pages/demo/demo.gleam
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import components/ui/slider.{slider}
import components/ui/select.{select}
import lustre/attribute.{class}
import lustre/element.{type Element}
import lustre/element/html.{div}
import lustre/element/html.{div, option}

pub fn demo() -> Element(a) {
div([class("flex flex-col gap-2 py-2 w-full max-w-xs")], [
slider([slider.solid(slider.Neutral), slider.sm()]),
slider([slider.solid(slider.Neutral), slider.md()]),
slider([slider.solid(slider.Neutral), slider.lg()]),
div([class("flex flex-col flex-wrap gap-4 justify-center w-full pt-8")], [
select([select.outlined(select.Neutral), select.md()], [option([], "Neutral")]),
select([select.outlined(select.Primary), select.md()], [option([], "Primary")]),
select([select.outlined(select.Secondary), select.md()], [option([], "Secondary")]),
select([select.outlined(select.Success), select.md()], [option([], "Success")]),
select([select.outlined(select.Info), select.md()], [option([], "Info")]),
select([select.outlined(select.Warning), select.md()], [option([], "Warning")]),
select([select.outlined(select.Danger), select.md()], [option([], "Danger")]),
])
}
46 changes: 46 additions & 0 deletions app/src/pages/docs/components/select/attributes.gleam
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import components/ui/select.{select}
import lustre/element.{type Element}
import lustre/element/html.{option}
import pages/docs/sections/section

pub fn attributes() -> Element(a) {
section.attributes([
section.attribute(
"Size",
"
- `sm()`: Small Size
- `md()`: Medium Size
- `lg()`: Large Size
",
[
select([select.outlined(select.Neutral), select.sm()], [
option([], "Small"),
]),
select([select.outlined(select.Neutral), select.md()], [
option([], "Medium"),
]),
select([select.outlined(select.Neutral), select.lg()], [
option([], "Large"),
]),
],
size_code(),
),
])
}

fn size_code() -> String {
"
import components/ui/select.{select}
import lustre/attribute.{class}
import lustre/element.{type Element}
import lustre/element/html.{div, option}
pub fn demo() -> Element(a) {
div([class(\"flex flex-col flex-wrap gap-4 justify-center w-full\")], [
select([select.outlined(select.Neutral), select.sm()], [option([], \"Small\")]),
select([select.outlined(select.Neutral), select.md()], [option([], \"Medium\")]),
select([select.outlined(select.Neutral), select.lg()], [option([], \"Large\")]),
])
}
"
}
17 changes: 17 additions & 0 deletions app/src/pages/docs/components/select/select.gleam
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import components/prose.{prose}
import lustre/element.{type Element}
import pages/docs/components/select/attributes.{attributes}
import pages/docs/components/select/variants.{variants}
import pages/docs/sections/section

pub fn docs() -> Element(a) {
prose([], [
section.intro(
"Select",
"Select components are used for collecting user provided information from a list of options.",
),
section.installation("gleam run -m gleez add select"),
variants(),
attributes(),
])
}
Loading

0 comments on commit f51a41d

Please sign in to comment.