From 872cc52963b40c4f8db1a6f4e4eb792ee7882416 Mon Sep 17 00:00:00 2001 From: mahcodes Date: Thu, 9 May 2024 17:41:12 +0300 Subject: [PATCH 01/17] feat: new `kbd` component --- app/src/components/ui/kbd.gleam | 178 ++++++++++++++++++ app/src/gleez_ui.gleam | 2 + app/src/model/route.gleam | 5 + app/src/pages/demo/demo.gleam | 16 +- .../docs/components/kbd/attributes.gleam | 39 ++++ .../pages/docs/components/kbd/examples.gleam | 119 ++++++++++++ app/src/pages/docs/components/kbd/kbd.gleam | 18 ++ .../pages/docs/components/kbd/variants.gleam | 148 +++++++++++++++ app/src/pages/page.gleam | 3 + 9 files changed, 518 insertions(+), 10 deletions(-) create mode 100644 app/src/components/ui/kbd.gleam create mode 100644 app/src/pages/docs/components/kbd/attributes.gleam create mode 100644 app/src/pages/docs/components/kbd/examples.gleam create mode 100644 app/src/pages/docs/components/kbd/kbd.gleam create mode 100644 app/src/pages/docs/components/kbd/variants.gleam diff --git a/app/src/components/ui/kbd.gleam b/app/src/components/ui/kbd.gleam new file mode 100644 index 0000000..6fe6ec2 --- /dev/null +++ b/app/src/components/ui/kbd.gleam @@ -0,0 +1,178 @@ +import gleam/string +import lustre/attribute.{type Attribute, class} +import lustre/element.{type Element, text} +import lustre/element/html.{abbr} + +pub type Colors { + Neutral + Primary + Secondary + Success + Info + Warning + Danger +} + +pub fn kbd( + attributes: List(Attribute(a)), + children: List(Element(a)), +) -> Element(a) { + html.kbd( + [ + class( + [ + "shadow-[0px_.25rem_0px_0px]", + "inline-flex gap-1 items-center justify-center transition-all [&_abbr]:no-underline leading-normal", + ] + |> string.join(" "), + ), + ..attributes + ], + children, + ) +} + +pub fn solid(color: Colors) -> Attribute(a) { + case color { + Neutral -> "bg-neutral shadow-neutral/50 text-neutral-foreground" + Primary -> "bg-primary shadow-primary/50 text-primary-foreground" + Secondary -> "bg-secondary shadow-secondary/50 text-secondary-foreground" + Success -> "bg-success shadow-success/50 text-success-foreground" + Info -> "bg-info shadow-info/50 text-info-foreground" + Warning -> "bg-warning shadow-warning/50 text-warning-foreground" + Danger -> "bg-danger shadow-danger/50 text-danger-foreground" + } + |> class +} + +pub fn outlined(color: Colors) -> Attribute(a) { + case color { + Neutral -> "text-neutral shadow-neutral border-neutral" + Primary -> "text-primary shadow-primary border-primary" + Secondary -> "text-secondary shadow-secondary border-secondary" + Success -> "text-success shadow-success border-success" + Info -> "text-info shadow-info border-info" + Warning -> "text-warning shadow-warning border-warning" + Danger -> "text-danger shadow-danger border-danger" + } + |> string.append(" border-2") + |> class +} + +pub fn light(color: Colors) -> Attribute(a) { + case color { + Neutral -> "text-neutral shadow-neutral" + Primary -> "text-primary shadow-primary" + Secondary -> "text-secondary shadow-secondary" + Success -> "text-success shadow-success" + Info -> "text-info shadow-info" + Warning -> "text-warning shadow-warning" + Danger -> "text-danger shadow-danger" + } + |> class +} + +pub fn flat(color: Colors) -> Attribute(a) { + case color { + Neutral -> "text-neutral shadow-neutral bg-neutral/20" + Primary -> "text-primary shadow-primary bg-primary/20" + Secondary -> "text-secondary shadow-secondary bg-secondary/20" + Success -> "text-success shadow-success bg-success/20" + Info -> "text-info shadow-info bg-info/20" + Warning -> "text-warning shadow-warning bg-warning/20" + Danger -> "text-danger shadow-danger bg-danger/20" + } + |> class +} + +fn title(t: String) -> Attribute(a) { + attribute.attribute("title", t) +} + +pub fn command() -> Element(a) { + abbr([title("Command")], [text("⌘")]) +} + +pub fn shift() -> Element(a) { + abbr([title("Shift")], [text("⇧")]) +} + +pub fn ctrl() -> Element(a) { + abbr([title("Ctrl")], [text("⌃")]) +} + +pub fn option() -> Element(a) { + abbr([title("Option")], [text("⌥")]) +} + +pub fn enter() -> Element(a) { + abbr([title("Enter")], [text("↵")]) +} + +pub fn delete() -> Element(a) { + abbr([title("Delete")], [text("⌫")]) +} + +pub fn escape() -> Element(a) { + abbr([title("Escape")], [text("⎋")]) +} + +pub fn tab() -> Element(a) { + abbr([title("Tab")], [text("⇥")]) +} + +pub fn capslock() -> Element(a) { + abbr([title("Caps Lock")], [text("⇪")]) +} + +pub fn up() -> Element(a) { + abbr([title("Up")], [text("↑")]) +} + +pub fn right() -> Element(a) { + abbr([title("Right")], [text("→")]) +} + +pub fn down() -> Element(a) { + abbr([title("Down")], [text("↓")]) +} + +pub fn left() -> Element(a) { + abbr([title("Left")], [text("←")]) +} + +pub fn pageup() -> Element(a) { + abbr([title("Page Up")], [text("⇞")]) +} + +pub fn pagedown() -> Element(a) { + abbr([title("Page Down")], [text("⇟")]) +} + +pub fn home() -> Element(a) { + abbr([title("Home")], [text("↖")]) +} + +pub fn end() -> Element(a) { + abbr([title("End")], [text("↘")]) +} + +pub fn help() -> Element(a) { + abbr([title("Help")], [text("?")]) +} + +pub fn space() -> Element(a) { + abbr([title("Space")], [text("␣")]) +} + +pub fn sm() -> Attribute(a) { + class("px-1.5 py-0.5 text-xs rounded-sm") +} + +pub fn md() -> Attribute(a) { + class("px-1.5 py-0.5 text-sm rounded-sm") +} + +pub fn lg() -> Attribute(a) { + class("px-2 py-0.5 text-base rounded-md") +} diff --git a/app/src/gleez_ui.gleam b/app/src/gleez_ui.gleam index 0baf233..4fadc7c 100644 --- a/app/src/gleez_ui.gleam +++ b/app/src/gleez_ui.gleam @@ -45,6 +45,7 @@ fn on_url_change(uri: Uri) -> Msg { ["docs", "components", "badge"] -> OnRouteChange(route.Badge) ["docs", "components", "breadcrumbs"] -> OnRouteChange(route.Breadcrumbs) ["docs", "components", "switch"] -> OnRouteChange(route.Switch) + ["docs", "components", "kbd"] -> OnRouteChange(route.Kbd) _ -> OnRouteChange(route.Home) } } @@ -131,6 +132,7 @@ fn with_aside(model: Model) -> Element(Msg) { route.Badge -> page.badge() route.Breadcrumbs -> page.breadcrumbs() route.Switch -> page.switch() + route.Kbd -> page.kbd() _ -> page.home() }, ]), diff --git a/app/src/model/route.gleam b/app/src/model/route.gleam index 2f7ab28..5758b2b 100644 --- a/app/src/model/route.gleam +++ b/app/src/model/route.gleam @@ -21,6 +21,7 @@ pub type Pages { Badge Breadcrumbs Switch + Kbd } pub const home = "/" @@ -59,6 +60,8 @@ pub const breadcrumbs = "/docs/components/breadcrumbs" pub const switch = "/docs/components/switch" +pub const kbd = "/docs/components/kbd" + pub type Page { Page(path: String, sub_pages: List(Page)) } @@ -79,6 +82,7 @@ pub fn pages() -> List(Page) { Page(badge, []), Page(breadcrumbs, []), Page(switch, []), + Page(kbd, []), ] |> sort_pages, ), @@ -104,6 +108,7 @@ pub fn to_path(page: Pages) -> String { Badge -> badge Breadcrumbs -> breadcrumbs Switch -> switch + Kbd -> kbd } } diff --git a/app/src/pages/demo/demo.gleam b/app/src/pages/demo/demo.gleam index 334c844..a88a9c5 100644 --- a/app/src/pages/demo/demo.gleam +++ b/app/src/pages/demo/demo.gleam @@ -1,18 +1,14 @@ -import components/ui/switch.{switch} -import lustre/attribute.{class, disabled} +import components/ui/kbd.{kbd} +import lustre/attribute.{class} import lustre/element.{type Element, text} import lustre/element/html.{div} pub fn demo() -> Element(a) { div([class("flex flex-wrap gap-4 items-center justify-center w-full")], [ - switch([switch.solid(switch.Neutral), switch.sm(), disabled(True)], [ - text("Disabled"), - ]), - switch([switch.outlined(switch.Neutral), switch.sm(), disabled(True)], [ - text("Disabled"), - ]), - switch([switch.ghost(switch.Neutral), switch.sm(), disabled(True)], [ - text("Disabled"), + kbd([kbd.outlined(kbd.Neutral), kbd.md()], [ + kbd.option(), + kbd.command(), + text("K"), ]), ]) } diff --git a/app/src/pages/docs/components/kbd/attributes.gleam b/app/src/pages/docs/components/kbd/attributes.gleam new file mode 100644 index 0000000..5caec50 --- /dev/null +++ b/app/src/pages/docs/components/kbd/attributes.gleam @@ -0,0 +1,39 @@ +import components/ui/kbd.{kbd} +import lustre/element.{type Element, text} +import pages/docs/sections/section + +pub fn attributes() -> Element(a) { + section.attributes([ + section.attribute( + "Size", + " +- `sm()`: Small Size +- `md()`: Medium Size +- `lg()`: Large Size + ", + [ + kbd([kbd.outlined(kbd.Neutral), kbd.sm()], [kbd.command(), text("K")]), + kbd([kbd.outlined(kbd.Neutral), kbd.md()], [kbd.command(), text("K")]), + kbd([kbd.outlined(kbd.Neutral), kbd.lg()], [kbd.command(), text("K")]), + ], + size_code(), + ), + ]) +} + +fn size_code() -> String { + " +import components/ui/kbd.{kbd} +import lustre/attribute.{class} +import lustre/element.{type Element, text} +import lustre/element/html.{div} + +pub fn demo() -> Element(a) { + div([class(\"flex flex-wrap gap-4 items-center justify-center w-full\")], [ + kbd([kbd.outlined(kbd.Neutral), kbd.sm()], [kbd.command(), text(\"K\")]), + kbd([kbd.outlined(kbd.Neutral), kbd.md()], [kbd.command(), text(\"K\")]), + kbd([kbd.outlined(kbd.Neutral), kbd.lg()], [kbd.command(), text(\"K\")]), + ]) +} +" +} diff --git a/app/src/pages/docs/components/kbd/examples.gleam b/app/src/pages/docs/components/kbd/examples.gleam new file mode 100644 index 0000000..32ab40b --- /dev/null +++ b/app/src/pages/docs/components/kbd/examples.gleam @@ -0,0 +1,119 @@ +import components/ui/kbd.{kbd} +import lustre/element.{type Element, text} +import pages/docs/sections/section + +pub fn examples() -> Element(a) { + section.examples([ + section.example( + "Keys", + "", + [ + kbd([kbd.outlined(kbd.Neutral), kbd.md()], [ + kbd.command(), + text("Command"), + ]), + kbd([kbd.outlined(kbd.Neutral), kbd.md()], [kbd.shift(), text("Shift")]), + kbd([kbd.outlined(kbd.Neutral), kbd.md()], [kbd.ctrl(), text("Ctrl")]), + kbd([kbd.outlined(kbd.Neutral), kbd.md()], [ + kbd.option(), + text("Option"), + ]), + kbd([kbd.outlined(kbd.Neutral), kbd.md()], [kbd.enter(), text("Enter")]), + kbd([kbd.outlined(kbd.Neutral), kbd.md()], [ + kbd.delete(), + text("Delete"), + ]), + kbd([kbd.outlined(kbd.Neutral), kbd.md()], [ + kbd.escape(), + text("Escape"), + ]), + kbd([kbd.outlined(kbd.Neutral), kbd.md()], [kbd.tab(), text("Tab")]), + kbd([kbd.outlined(kbd.Neutral), kbd.md()], [ + kbd.capslock(), + text("Caps Lock"), + ]), + kbd([kbd.outlined(kbd.Neutral), kbd.md()], [kbd.up(), text("Up")]), + kbd([kbd.outlined(kbd.Neutral), kbd.md()], [kbd.right(), text("Right")]), + kbd([kbd.outlined(kbd.Neutral), kbd.md()], [kbd.down(), text("Down")]), + kbd([kbd.outlined(kbd.Neutral), kbd.md()], [kbd.left(), text("Left")]), + kbd([kbd.outlined(kbd.Neutral), kbd.md()], [ + kbd.pageup(), + text("Page Up"), + ]), + kbd([kbd.outlined(kbd.Neutral), kbd.md()], [ + kbd.pagedown(), + text("Page Down"), + ]), + kbd([kbd.outlined(kbd.Neutral), kbd.md()], [kbd.home(), text("Home")]), + kbd([kbd.outlined(kbd.Neutral), kbd.md()], [kbd.end(), text("End")]), + kbd([kbd.outlined(kbd.Neutral), kbd.md()], [kbd.help(), text("Help")]), + kbd([kbd.outlined(kbd.Neutral), kbd.md()], [kbd.space(), text("Space")]), + ], + keys_code(), + ), + section.example( + "Key Combination", + "", + [ + kbd([kbd.outlined(kbd.Neutral), kbd.md()], [ + kbd.command(), + kbd.shift(), + text("K"), + ]), + ], + key_combination_code(), + ), + ]) +} + +fn keys_code() -> String { + " +import components/ui/kbd.{kbd} +import lustre/attribute.{class} +import lustre/element.{type Element, text} +import lustre/element/html.{div} + +pub fn demo() -> Element(a) { + div([class(\"flex flex-wrap gap-4 items-center justify-center w-full\")], [ + kbd([kbd.outlined(kbd.Neutral), kbd.md()], [kbd.command(), text(\"Command\")]), + kbd([kbd.outlined(kbd.Neutral), kbd.md()], [kbd.shift(), text(\"Shift\")]), + kbd([kbd.outlined(kbd.Neutral), kbd.md()], [kbd.ctrl(), text(\"Ctrl\")]), + kbd([kbd.outlined(kbd.Neutral), kbd.md()], [kbd.option(), text(\"Option\")]), + kbd([kbd.outlined(kbd.Neutral), kbd.md()], [kbd.enter(), text(\"Enter\")]), + kbd([kbd.outlined(kbd.Neutral), kbd.md()], [kbd.delete(), text(\"Delete\")]), + kbd([kbd.outlined(kbd.Neutral), kbd.md()], [kbd.escape(), text(\"Escape\")]), + kbd([kbd.outlined(kbd.Neutral), kbd.md()], [kbd.tab(), text(\"Tab\")]), + kbd([kbd.outlined(kbd.Neutral), kbd.md()], [kbd.capslock(), text(\"Caps Lock\")]), + kbd([kbd.outlined(kbd.Neutral), kbd.md()], [kbd.up(), text(\"Up\")]), + kbd([kbd.outlined(kbd.Neutral), kbd.md()], [kbd.right(), text(\"Right\")]), + kbd([kbd.outlined(kbd.Neutral), kbd.md()], [kbd.down(), text(\"Down\")]), + kbd([kbd.outlined(kbd.Neutral), kbd.md()], [kbd.left(), text(\"Left\")]), + kbd([kbd.outlined(kbd.Neutral), kbd.md()], [kbd.pageup(), text(\"Page Up\")]), + kbd([kbd.outlined(kbd.Neutral), kbd.md()], [kbd.pagedown(), text(\"Page Down\")]), + kbd([kbd.outlined(kbd.Neutral), kbd.md()], [kbd.home(), text(\"Home\")]), + kbd([kbd.outlined(kbd.Neutral), kbd.md()], [kbd.end(), text(\"End\")]), + kbd([kbd.outlined(kbd.Neutral), kbd.md()], [kbd.help(), text(\"Help\")]), + kbd([kbd.outlined(kbd.Neutral), kbd.md()], [kbd.space(), text(\"Space\")]), + ]) +} +" +} + +fn key_combination_code() -> String { + " +import components/ui/kbd.{kbd} +import lustre/attribute.{class} +import lustre/element.{type Element, text} +import lustre/element/html.{div} + +pub fn demo() -> Element(a) { + div([class(\"flex flex-wrap gap-4 items-center justify-center w-full\")], [ + kbd([kbd.outlined(kbd.Neutral), kbd.md()], [ + kbd.command(), + kbd.shift(), + text(\"K\"), + ]), + ]) +} +" +} diff --git a/app/src/pages/docs/components/kbd/kbd.gleam b/app/src/pages/docs/components/kbd/kbd.gleam new file mode 100644 index 0000000..92dddb6 --- /dev/null +++ b/app/src/pages/docs/components/kbd/kbd.gleam @@ -0,0 +1,18 @@ +import components/prose.{prose} +import lustre/element.{type Element} +import pages/docs/components/kbd/attributes.{attributes} +import pages/docs/components/kbd/examples.{examples} +import pages/docs/components/kbd/variants.{variants} +import pages/docs/sections/section + +pub fn docs() -> Element(a) { + prose([], [ + section.intro( + "Kbd", + "The keyboard key component exists to show which key or combination of keys performs a given action.",), + section.installation("gleam run -m gleez add kbd"), + variants(), + attributes(), + examples(), + ]) +} diff --git a/app/src/pages/docs/components/kbd/variants.gleam b/app/src/pages/docs/components/kbd/variants.gleam new file mode 100644 index 0000000..876533f --- /dev/null +++ b/app/src/pages/docs/components/kbd/variants.gleam @@ -0,0 +1,148 @@ +import components/ui/kbd.{kbd} +import lustre/element.{type Element, text} +import pages/docs/sections/section + +pub fn variants() -> Element(a) { + section.variants([ + section.variant( + "Solid", + "", + [ + kbd([kbd.solid(kbd.Neutral), kbd.md()], [kbd.command(), text("K")]), + kbd([kbd.solid(kbd.Primary), kbd.md()], [kbd.command(), text("K")]), + kbd([kbd.solid(kbd.Secondary), kbd.md()], [kbd.command(), text("K")]), + kbd([kbd.solid(kbd.Success), kbd.md()], [kbd.command(), text("K")]), + kbd([kbd.solid(kbd.Info), kbd.md()], [kbd.command(), text("K")]), + kbd([kbd.solid(kbd.Warning), kbd.md()], [kbd.command(), text("K")]), + kbd([kbd.solid(kbd.Danger), kbd.md()], [kbd.command(), text("K")]), + ], + solid_code(), + ), + section.variant( + "Outlined", + "", + [ + kbd([kbd.outlined(kbd.Neutral), kbd.md()], [kbd.command(), text("K")]), + kbd([kbd.outlined(kbd.Primary), kbd.md()], [kbd.command(), text("K")]), + kbd([kbd.outlined(kbd.Secondary), kbd.md()], [kbd.command(), text("K")]), + kbd([kbd.outlined(kbd.Success), kbd.md()], [kbd.command(), text("K")]), + kbd([kbd.outlined(kbd.Info), kbd.md()], [kbd.command(), text("K")]), + kbd([kbd.outlined(kbd.Warning), kbd.md()], [kbd.command(), text("K")]), + kbd([kbd.outlined(kbd.Danger), kbd.md()], [kbd.command(), text("K")]), + ], + outlined_code(), + ), + section.variant( + "Flat", + "", + [ + kbd([kbd.flat(kbd.Neutral), kbd.md()], [kbd.command(), text("K")]), + kbd([kbd.flat(kbd.Primary), kbd.md()], [kbd.command(), text("K")]), + kbd([kbd.flat(kbd.Secondary), kbd.md()], [kbd.command(), text("K")]), + kbd([kbd.flat(kbd.Success), kbd.md()], [kbd.command(), text("K")]), + kbd([kbd.flat(kbd.Info), kbd.md()], [kbd.command(), text("K")]), + kbd([kbd.flat(kbd.Warning), kbd.md()], [kbd.command(), text("K")]), + kbd([kbd.flat(kbd.Danger), kbd.md()], [kbd.command(), text("K")]), + ], + flat_code(), + ), + section.variant( + "Light", + "", + [ + kbd([kbd.light(kbd.Neutral), kbd.md()], [kbd.command(), text("K")]), + kbd([kbd.light(kbd.Primary), kbd.md()], [kbd.command(), text("K")]), + kbd([kbd.light(kbd.Secondary), kbd.md()], [kbd.command(), text("K")]), + kbd([kbd.light(kbd.Success), kbd.md()], [kbd.command(), text("K")]), + kbd([kbd.light(kbd.Info), kbd.md()], [kbd.command(), text("K")]), + kbd([kbd.light(kbd.Warning), kbd.md()], [kbd.command(), text("K")]), + kbd([kbd.light(kbd.Danger), kbd.md()], [kbd.command(), text("K")]), + ], + light_code(), + ), + ]) +} + +fn solid_code() -> String { + " +import components/ui/kbd.{kbd} +import lustre/attribute.{class} +import lustre/element.{type Element, text} +import lustre/element/html.{div} + +pub fn demo() -> Element(a) { + div([class(\"flex flex-wrap gap-4 items-center justify-center w-full\")], [ + kbd([kbd.solid(kbd.Neutral), kbd.md()], [kbd.command(), text(\"K\")]), + kbd([kbd.solid(kbd.Primary), kbd.md()], [kbd.command(), text(\"K\")]), + kbd([kbd.solid(kbd.Secondary), kbd.md()], [kbd.command(), text(\"K\")]), + kbd([kbd.solid(kbd.Success), kbd.md()], [kbd.command(), text(\"K\")]), + kbd([kbd.solid(kbd.Info), kbd.md()], [kbd.command(), text(\"K\")]), + kbd([kbd.solid(kbd.Warning), kbd.md()], [kbd.command(), text(\"K\")]), + kbd([kbd.solid(kbd.Danger), kbd.md()], [kbd.command(), text(\"K\")]), + ]) +} +" +} + +fn outlined_code() -> String { + " +import components/ui/kbd.{kbd} +import lustre/attribute.{class} +import lustre/element.{type Element, text} +import lustre/element/html.{div} + +pub fn demo() -> Element(a) { + div([class(\"flex flex-wrap gap-4 items-center justify-center w-full\")], [ + kbd([kbd.outlined(kbd.Neutral), kbd.md()], [kbd.command(), text(\"K\")]), + kbd([kbd.outlined(kbd.Primary), kbd.md()], [kbd.command(), text(\"K\")]), + kbd([kbd.outlined(kbd.Secondary), kbd.md()], [kbd.command(), text(\"K\")]), + kbd([kbd.outlined(kbd.Success), kbd.md()], [kbd.command(), text(\"K\")]), + kbd([kbd.outlined(kbd.Info), kbd.md()], [kbd.command(), text(\"K\")]), + kbd([kbd.outlined(kbd.Warning), kbd.md()], [kbd.command(), text(\"K\")]), + kbd([kbd.outlined(kbd.Danger), kbd.md()], [kbd.command(), text(\"K\")]), + ]) +} +" +} + +fn flat_code() -> String { + " +import components/ui/kbd.{kbd} +import lustre/attribute.{class} +import lustre/element.{type Element, text} +import lustre/element/html.{div} + +pub fn demo() -> Element(a) { + div([class(\"flex flex-wrap gap-4 items-center justify-center w-full\")], [ + kbd([kbd.flat(kbd.Neutral), kbd.md()], [kbd.command(), text(\"K\")]), + kbd([kbd.flat(kbd.Primary), kbd.md()], [kbd.command(), text(\"K\")]), + kbd([kbd.flat(kbd.Secondary), kbd.md()], [kbd.command(), text(\"K\")]), + kbd([kbd.flat(kbd.Success), kbd.md()], [kbd.command(), text(\"K\")]), + kbd([kbd.flat(kbd.Info), kbd.md()], [kbd.command(), text(\"K\")]), + kbd([kbd.flat(kbd.Warning), kbd.md()], [kbd.command(), text(\"K\")]), + kbd([kbd.flat(kbd.Danger), kbd.md()], [kbd.command(), text(\"K\")]), + ]) +} +" +} + +fn light_code() -> String { + " +import components/ui/kbd.{kbd} +import lustre/attribute.{class} +import lustre/element.{type Element, text} +import lustre/element/html.{div} + +pub fn demo() -> Element(a) { + div([class(\"flex flex-wrap gap-4 items-center justify-center w-full\")], [ + kbd([kbd.light(kbd.Neutral), kbd.md()], [kbd.command(), text(\"K\")]), + kbd([kbd.light(kbd.Primary), kbd.md()], [kbd.command(), text(\"K\")]), + kbd([kbd.light(kbd.Secondary), kbd.md()], [kbd.command(), text(\"K\")]), + kbd([kbd.light(kbd.Success), kbd.md()], [kbd.command(), text(\"K\")]), + kbd([kbd.light(kbd.Info), kbd.md()], [kbd.command(), text(\"K\")]), + kbd([kbd.light(kbd.Warning), kbd.md()], [kbd.command(), text(\"K\")]), + kbd([kbd.light(kbd.Danger), kbd.md()], [kbd.command(), text(\"K\")]), + ]) +} +" +} diff --git a/app/src/pages/page.gleam b/app/src/pages/page.gleam index 33b9953..0543a33 100644 --- a/app/src/pages/page.gleam +++ b/app/src/pages/page.gleam @@ -7,6 +7,7 @@ import pages/docs/components/button/button import pages/docs/components/chip/chip import pages/docs/components/divider/divider import pages/docs/components/input/input +import pages/docs/components/kbd/kbd import pages/docs/components/link/link import pages/docs/components/switch/switch import pages/docs/components/tooltip/tooltip @@ -48,3 +49,5 @@ pub const badge = badge.docs pub const breadcrumbs = breadcrumbs.docs pub const switch = switch.docs + +pub const kbd = kbd.docs From d4fd7d129ced7ecb1ad6fd7faafde4c2e5afa2a0 Mon Sep 17 00:00:00 2001 From: mahcodes Date: Thu, 9 May 2024 21:34:20 +0300 Subject: [PATCH 02/17] feat: new `checkbox` component --- app/src/components/ui/checkbox.gleam | 107 ++++++++++ app/src/gleez_ui.gleam | 2 + app/src/model/route.gleam | 5 + app/src/pages/demo/demo.gleam | 18 +- .../docs/components/checkbox/attributes.gleam | 45 ++++ .../docs/components/checkbox/checkbox.gleam | 19 ++ .../docs/components/checkbox/examples.gleam | 48 +++++ .../docs/components/checkbox/variants.gleam | 198 ++++++++++++++++++ app/src/pages/page.gleam | 3 + 9 files changed, 438 insertions(+), 7 deletions(-) create mode 100644 app/src/components/ui/checkbox.gleam create mode 100644 app/src/pages/docs/components/checkbox/attributes.gleam create mode 100644 app/src/pages/docs/components/checkbox/checkbox.gleam create mode 100644 app/src/pages/docs/components/checkbox/examples.gleam create mode 100644 app/src/pages/docs/components/checkbox/variants.gleam diff --git a/app/src/components/ui/checkbox.gleam b/app/src/components/ui/checkbox.gleam new file mode 100644 index 0000000..61b40c7 --- /dev/null +++ b/app/src/components/ui/checkbox.gleam @@ -0,0 +1,107 @@ +import gleam/string +import lustre/attribute.{type Attribute, class, type_} +import lustre/element.{type Element} +import lustre/element/html.{input, label, span} + +pub type Colors { + Neutral + Primary + Secondary + Success + Info + Warning + Danger +} + +pub fn checkbox( + attributes: List(Attribute(a)), + children: List(Element(a)), +) -> Element(a) { + label([class("inline-flex items-center gap-2")], [ + input([ + type_("checkbox"), + class( + [ + "inline-flex items-center justify-center p-0.5 appearance-none transition-all rounded", + "enabled:cursor-pointer disabled:cursor-not-allowed disabled:opacity-50", + "[&:disabled+span]:opacity-50 [&:enabled+span]:cursor-pointer [&:disabled+span]:cursor-not-allowed", + "checked:before:content-['✔'] before:inset-0 before:m-auto before:leading-[0]", + ] + |> string.join(" "), + ), + ..attributes + ]), + span([], children), + ]) +} + +pub fn solid(color: Colors) -> Attribute(a) { + case color { + Neutral -> "bg-neutral before:text-neutral-foreground" + Primary -> "bg-primary before:text-primary-foreground" + Secondary -> "bg-secondary before:text-secondary-foreground" + Success -> "bg-success before:text-success-foreground" + Info -> "bg-info before:text-info-foreground" + Warning -> "bg-warning before:text-warning-foreground" + Danger -> "bg-danger before:text-danger-foreground" + } + |> class +} + +pub fn outlined(color: Colors) -> Attribute(a) { + case color { + Neutral -> "border-neutral before:text-neutral" + Primary -> "border-primary before:text-primary" + Secondary -> "border-secondary before:text-secondary" + Success -> "border-success before:text-success" + Info -> "border-info before:text-info" + Warning -> "border-warning before:text-warning" + Danger -> "border-danger before:text-danger" + } + |> string.append(" border") + |> class +} + +pub fn flat(color: Colors) -> Attribute(a) { + case color { + Neutral -> "bg-neutral/20 before:text-neutral" + Primary -> "bg-primary/20 before:text-primary" + Secondary -> "bg-secondary/20 before:text-secondary" + Success -> "bg-success/20 before:text-success" + Info -> "bg-info/20 before:text-info" + Warning -> "bg-warning/20 before:text-warning" + Danger -> "bg-danger/20 before:text-danger" + } + |> class +} + +pub fn ghost(color: Colors) -> Attribute(a) { + case color { + Neutral -> + "checked:bg-neutral before:text-neutral-foreground border-neutral" + Primary -> + "checked:bg-primary before:text-primary-foreground border-primary" + Secondary -> + "checked:bg-secondary before:text-secondary-foreground border-secondary" + Success -> + "checked:bg-success before:text-success-foreground border-success" + Info -> "checked:bg-info before:text-info-foreground border-info" + Warning -> + "checked:bg-warning before:text-warning-foreground border-warning" + Danger -> "checked:bg-danger before:text-danger-foreground border-danger" + } + |> string.append(" border") + |> class +} + +pub fn sm() -> Attribute(a) { + class("w-3 h-3 text-sm [&+span]:text-sm") +} + +pub fn md() -> Attribute(a) { + class("w-4 h-4 text-base [&+span]:text-base") +} + +pub fn lg() -> Attribute(a) { + class("w-5 h-5 text-lg [&+span]:text-lg") +} diff --git a/app/src/gleez_ui.gleam b/app/src/gleez_ui.gleam index 4fadc7c..76d9bbd 100644 --- a/app/src/gleez_ui.gleam +++ b/app/src/gleez_ui.gleam @@ -46,6 +46,7 @@ fn on_url_change(uri: Uri) -> Msg { ["docs", "components", "breadcrumbs"] -> OnRouteChange(route.Breadcrumbs) ["docs", "components", "switch"] -> OnRouteChange(route.Switch) ["docs", "components", "kbd"] -> OnRouteChange(route.Kbd) + ["docs", "components", "checkbox"] -> OnRouteChange(route.Checkbox) _ -> OnRouteChange(route.Home) } } @@ -133,6 +134,7 @@ fn with_aside(model: Model) -> Element(Msg) { route.Breadcrumbs -> page.breadcrumbs() route.Switch -> page.switch() route.Kbd -> page.kbd() + route.Checkbox -> page.checkbox() _ -> page.home() }, ]), diff --git a/app/src/model/route.gleam b/app/src/model/route.gleam index 5758b2b..689872b 100644 --- a/app/src/model/route.gleam +++ b/app/src/model/route.gleam @@ -22,6 +22,7 @@ pub type Pages { Breadcrumbs Switch Kbd + Checkbox } pub const home = "/" @@ -62,6 +63,8 @@ pub const switch = "/docs/components/switch" pub const kbd = "/docs/components/kbd" +pub const checkbox = "/docs/components/checkbox" + pub type Page { Page(path: String, sub_pages: List(Page)) } @@ -83,6 +86,7 @@ pub fn pages() -> List(Page) { Page(breadcrumbs, []), Page(switch, []), Page(kbd, []), + Page(checkbox, []), ] |> sort_pages, ), @@ -109,6 +113,7 @@ pub fn to_path(page: Pages) -> String { Breadcrumbs -> breadcrumbs Switch -> switch Kbd -> kbd + Checkbox -> checkbox } } diff --git a/app/src/pages/demo/demo.gleam b/app/src/pages/demo/demo.gleam index a88a9c5..6f7ea12 100644 --- a/app/src/pages/demo/demo.gleam +++ b/app/src/pages/demo/demo.gleam @@ -1,14 +1,18 @@ -import components/ui/kbd.{kbd} -import lustre/attribute.{class} +import components/ui/checkbox.{checkbox} +import lustre/attribute.{checked, class, disabled} import lustre/element.{type Element, text} import lustre/element/html.{div} pub fn demo() -> Element(a) { div([class("flex flex-wrap gap-4 items-center justify-center w-full")], [ - kbd([kbd.outlined(kbd.Neutral), kbd.md()], [ - kbd.option(), - kbd.command(), - text("K"), - ]), + checkbox( + [ + checkbox.solid(checkbox.Neutral), + checkbox.md(), + checked(True), + disabled(True), + ], + [text("Disabled")], + ), ]) } diff --git a/app/src/pages/docs/components/checkbox/attributes.gleam b/app/src/pages/docs/components/checkbox/attributes.gleam new file mode 100644 index 0000000..3305461 --- /dev/null +++ b/app/src/pages/docs/components/checkbox/attributes.gleam @@ -0,0 +1,45 @@ +import components/ui/checkbox.{checkbox} +import lustre/element.{type Element, text} +import pages/docs/sections/section + +pub fn attributes() -> Element(a) { + section.attributes([ + section.attribute( + "Size", + " +- `sm()`: Small Size +- `md()`: Medium Size +- `lg()`: Large Size + ", + [ + checkbox([checkbox.solid(checkbox.Neutral), checkbox.sm()], [ + text("Small"), + ]), + checkbox([checkbox.solid(checkbox.Neutral), checkbox.md()], [ + text("Medium"), + ]), + checkbox([checkbox.solid(checkbox.Neutral), checkbox.lg()], [ + text("Large"), + ]), + ], + size_code(), + ), + ]) +} + +fn size_code() -> String { + " +import components/ui/checkbox.{checkbox} +import lustre/attribute.{class} +import lustre/element.{type Element, text} +import lustre/element/html.{div} + +pub fn demo() -> Element(a) { + div([class(\"flex flex-wrap gap-4 items-center justify-center w-full\")], [ + checkbox([checkbox.solid(checkbox.Neutral), checkbox.sm()], [text(\"Small\")]), + checkbox([checkbox.solid(checkbox.Neutral), checkbox.md()], [text(\"Medium\")]), + checkbox([checkbox.solid(checkbox.Neutral), checkbox.lg()], [text(\"Large\")]), + ]) +} +" +} diff --git a/app/src/pages/docs/components/checkbox/checkbox.gleam b/app/src/pages/docs/components/checkbox/checkbox.gleam new file mode 100644 index 0000000..b7eceba --- /dev/null +++ b/app/src/pages/docs/components/checkbox/checkbox.gleam @@ -0,0 +1,19 @@ +import components/prose.{prose} +import lustre/element.{type Element} +import pages/docs/components/checkbox/attributes.{attributes} +import pages/docs/components/checkbox/examples.{examples} +import pages/docs/components/checkbox/variants.{variants} +import pages/docs/sections/section + +pub fn docs() -> Element(a) { + prose([], [ + section.intro( + "Checkbox", + "Checkboxes allow the user to select one or more items from a set.", + ), + section.installation("gleam run -m gleez add checkbox"), + variants(), + attributes(), + examples(), + ]) +} diff --git a/app/src/pages/docs/components/checkbox/examples.gleam b/app/src/pages/docs/components/checkbox/examples.gleam new file mode 100644 index 0000000..0254f75 --- /dev/null +++ b/app/src/pages/docs/components/checkbox/examples.gleam @@ -0,0 +1,48 @@ +import components/ui/checkbox.{checkbox} +import lustre/attribute.{checked, disabled} +import lustre/element.{type Element, text} +import pages/docs/sections/section + +pub fn examples() -> Element(a) { + section.examples([ + section.example( + "Disabled", + "", + [ + checkbox( + [ + checkbox.solid(checkbox.Neutral), + checkbox.md(), + checked(True), + disabled(True), + ], + [text("Disabled")], + ), + ], + with_icons_code(), + ), + ]) +} + +fn with_icons_code() -> String { + " +import components/ui/checkbox.{checkbox} +import lustre/attribute.{checked, class, disabled} +import lustre/element.{type Element, text} +import lustre/element/html.{div} + +pub fn demo() -> Element(a) { + div([class(\"flex flex-wrap gap-4 items-center justify-center w-full\")], [ + checkbox( + [ + checkbox.solid(checkbox.Neutral), + checkbox.md(), + checked(True), + disabled(True), + ], + [text(\"Disabled\")], + ), + ]) +} +" +} diff --git a/app/src/pages/docs/components/checkbox/variants.gleam b/app/src/pages/docs/components/checkbox/variants.gleam new file mode 100644 index 0000000..7b22b2b --- /dev/null +++ b/app/src/pages/docs/components/checkbox/variants.gleam @@ -0,0 +1,198 @@ +import components/ui/checkbox.{checkbox} +import lustre/element.{type Element, text} +import pages/docs/sections/section + +pub fn variants() -> Element(a) { + section.variants([ + section.variant( + "Solid", + "", + [ + checkbox([checkbox.solid(checkbox.Neutral), checkbox.md()], [ + text("Neutral"), + ]), + checkbox([checkbox.solid(checkbox.Primary), checkbox.md()], [ + text("Primary"), + ]), + checkbox([checkbox.solid(checkbox.Secondary), checkbox.md()], [ + text("Secondary"), + ]), + checkbox([checkbox.solid(checkbox.Success), checkbox.md()], [ + text("Success"), + ]), + checkbox([checkbox.solid(checkbox.Info), checkbox.md()], [text("Info")]), + checkbox([checkbox.solid(checkbox.Warning), checkbox.md()], [ + text("Warning"), + ]), + checkbox([checkbox.solid(checkbox.Danger), checkbox.md()], [ + text("Danger"), + ]), + ], + solid_code(), + ), + section.variant( + "Outlined", + "", + [ + checkbox([checkbox.outlined(checkbox.Neutral), checkbox.md()], [ + text("Neutral"), + ]), + checkbox([checkbox.outlined(checkbox.Primary), checkbox.md()], [ + text("Primary"), + ]), + checkbox([checkbox.outlined(checkbox.Secondary), checkbox.md()], [ + text("Secondary"), + ]), + checkbox([checkbox.outlined(checkbox.Success), checkbox.md()], [ + text("Success"), + ]), + checkbox([checkbox.outlined(checkbox.Info), checkbox.md()], [ + text("Info"), + ]), + checkbox([checkbox.outlined(checkbox.Warning), checkbox.md()], [ + text("Warning"), + ]), + checkbox([checkbox.outlined(checkbox.Danger), checkbox.md()], [ + text("Danger"), + ]), + ], + outlined_code(), + ), + section.variant( + "Flat", + "", + [ + checkbox([checkbox.flat(checkbox.Neutral), checkbox.md()], [ + text("Neutral"), + ]), + checkbox([checkbox.flat(checkbox.Primary), checkbox.md()], [ + text("Primary"), + ]), + checkbox([checkbox.flat(checkbox.Secondary), checkbox.md()], [ + text("Secondary"), + ]), + checkbox([checkbox.flat(checkbox.Success), checkbox.md()], [ + text("Success"), + ]), + checkbox([checkbox.flat(checkbox.Info), checkbox.md()], [text("Info")]), + checkbox([checkbox.flat(checkbox.Warning), checkbox.md()], [ + text("Warning"), + ]), + checkbox([checkbox.flat(checkbox.Danger), checkbox.md()], [ + text("Danger"), + ]), + ], + flat_code(), + ), + section.variant( + "Ghost", + "", + [ + checkbox([checkbox.ghost(checkbox.Neutral), checkbox.md()], [ + text("Neutral"), + ]), + checkbox([checkbox.ghost(checkbox.Primary), checkbox.md()], [ + text("Primary"), + ]), + checkbox([checkbox.ghost(checkbox.Secondary), checkbox.md()], [ + text("Secondary"), + ]), + checkbox([checkbox.ghost(checkbox.Success), checkbox.md()], [ + text("Success"), + ]), + checkbox([checkbox.ghost(checkbox.Info), checkbox.md()], [text("Info")]), + checkbox([checkbox.ghost(checkbox.Warning), checkbox.md()], [ + text("Warning"), + ]), + checkbox([checkbox.ghost(checkbox.Danger), checkbox.md()], [ + text("Danger"), + ]), + ], + ghost_code(), + ), + ]) +} + +fn solid_code() -> String { + " +import components/ui/checkbox.{checkbox} +import lustre/attribute.{class} +import lustre/element.{type Element, text} +import lustre/element/html.{div} + +pub fn demo() -> Element(a) { + div([class(\"flex flex-wrap gap-4 items-center justify-center w-full\")], [ + checkbox([checkbox.solid(checkbox.Neutral), checkbox.md()], [text(\"Neutral\")]), + checkbox([checkbox.solid(checkbox.Primary), checkbox.md()], [text(\"Primary\")]), + checkbox([checkbox.solid(checkbox.Secondary), checkbox.md()], [text(\"Secondary\")]), + checkbox([checkbox.solid(checkbox.Success), checkbox.md()], [text(\"Success\")]), + checkbox([checkbox.solid(checkbox.Info), checkbox.md()], [text(\"Info\")]), + checkbox([checkbox.solid(checkbox.Warning), checkbox.md()], [text(\"Warning\")]), + checkbox([checkbox.solid(checkbox.Danger), checkbox.md()], [text(\"Danger\")]), + ]) +} +" +} + +fn outlined_code() -> String { + " +import components/ui/checkbox.{checkbox} +import lustre/attribute.{class} +import lustre/element.{type Element, text} +import lustre/element/html.{div} + +pub fn demo() -> Element(a) { + div([class(\"flex flex-wrap gap-4 items-center justify-center w-full\")], [ + checkbox([checkbox.outlined(checkbox.Neutral), checkbox.md()], [text(\"Neutral\")]), + checkbox([checkbox.outlined(checkbox.Primary), checkbox.md()], [text(\"Primary\")]), + checkbox([checkbox.outlined(checkbox.Secondary), checkbox.md()], [text(\"Secondary\")]), + checkbox([checkbox.outlined(checkbox.Success), checkbox.md()], [text(\"Success\")]), + checkbox([checkbox.outlined(checkbox.Info), checkbox.md()], [text(\"Info\")]), + checkbox([checkbox.outlined(checkbox.Warning), checkbox.md()], [text(\"Warning\")]), + checkbox([checkbox.outlined(checkbox.Danger), checkbox.md()], [text(\"Danger\")]), + ]) +} +" +} + +fn flat_code() -> String { + " +import components/ui/checkbox.{checkbox} +import lustre/attribute.{class} +import lustre/element.{type Element, text} +import lustre/element/html.{div} + +pub fn demo() -> Element(a) { + div([class(\"flex flex-wrap gap-4 items-center justify-center w-full\")], [ + checkbox([checkbox.flat(checkbox.Neutral), checkbox.md()], [text(\"Neutral\")]), + checkbox([checkbox.flat(checkbox.Primary), checkbox.md()], [text(\"Primary\")]), + checkbox([checkbox.flat(checkbox.Secondary), checkbox.md()], [text(\"Secondary\")]), + checkbox([checkbox.flat(checkbox.Success), checkbox.md()], [text(\"Success\")]), + checkbox([checkbox.flat(checkbox.Info), checkbox.md()], [text(\"Info\")]), + checkbox([checkbox.flat(checkbox.Warning), checkbox.md()], [text(\"Warning\")]), + checkbox([checkbox.flat(checkbox.Danger), checkbox.md()], [text(\"Danger\")]), + ]) +} +" +} + +fn ghost_code() -> String { + " +import components/ui/checkbox.{checkbox} +import lustre/attribute.{class} +import lustre/element.{type Element, text} +import lustre/element/html.{div} + +pub fn demo() -> Element(a) { + div([class(\"flex flex-wrap gap-4 items-center justify-center w-full\")], [ + checkbox([checkbox.ghost(checkbox.Neutral), checkbox.md()], [text(\"Neutral\")]), + checkbox([checkbox.ghost(checkbox.Primary), checkbox.md()], [text(\"Primary\")]), + checkbox([checkbox.ghost(checkbox.Secondary), checkbox.md()], [text(\"Secondary\")]), + checkbox([checkbox.ghost(checkbox.Success), checkbox.md()], [text(\"Success\")]), + checkbox([checkbox.ghost(checkbox.Info), checkbox.md()], [text(\"Info\")]), + checkbox([checkbox.ghost(checkbox.Warning), checkbox.md()], [text(\"Warning\")]), + checkbox([checkbox.ghost(checkbox.Danger), checkbox.md()], [text(\"Danger\")]), + ]) +} +" +} diff --git a/app/src/pages/page.gleam b/app/src/pages/page.gleam index 0543a33..d91411b 100644 --- a/app/src/pages/page.gleam +++ b/app/src/pages/page.gleam @@ -4,6 +4,7 @@ import pages/docs/components/avatar/avatar import pages/docs/components/badge/badge import pages/docs/components/breadcrumbs/breadcrumbs import pages/docs/components/button/button +import pages/docs/components/checkbox/checkbox import pages/docs/components/chip/chip import pages/docs/components/divider/divider import pages/docs/components/input/input @@ -51,3 +52,5 @@ pub const breadcrumbs = breadcrumbs.docs pub const switch = switch.docs pub const kbd = kbd.docs + +pub const checkbox = checkbox.docs From 0a7dc95da877aeec5debc501256fe84e098fa9a2 Mon Sep 17 00:00:00 2001 From: mahcodes Date: Fri, 10 May 2024 11:03:02 +0300 Subject: [PATCH 03/17] feat: new `spinner` component --- app/src/components/ui/spinner.gleam | 70 +++++++++++ app/src/gleez_ui.gleam | 4 +- app/src/model/route.gleam | 5 + app/src/pages/demo/demo.gleam | 18 +-- .../docs/components/spinner/attributes.gleam | 39 ++++++ .../docs/components/spinner/examples.gleam | 39 ++++++ .../docs/components/spinner/spinner.gleam | 18 +++ .../docs/components/spinner/variants.gleam | 113 ++++++++++++++++++ app/src/pages/page.gleam | 3 + 9 files changed, 296 insertions(+), 13 deletions(-) create mode 100644 app/src/components/ui/spinner.gleam create mode 100644 app/src/pages/docs/components/spinner/attributes.gleam create mode 100644 app/src/pages/docs/components/spinner/examples.gleam create mode 100644 app/src/pages/docs/components/spinner/spinner.gleam create mode 100644 app/src/pages/docs/components/spinner/variants.gleam diff --git a/app/src/components/ui/spinner.gleam b/app/src/components/ui/spinner.gleam new file mode 100644 index 0000000..2b299e5 --- /dev/null +++ b/app/src/components/ui/spinner.gleam @@ -0,0 +1,70 @@ +import gleam/string +import lustre/attribute.{type Attribute, class} +import lustre/element.{type Element, text} +import lustre/element/html.{div} + +pub type Colors { + Neutral + Primary + Secondary + Success + Info + Warning + Danger +} + +pub fn spinner(attributes: List(Attribute(a))) -> Element(a) { + div([class("animate-spin rounded-full"), ..attributes], []) +} + +pub fn solid(color: Colors) -> Attribute(a) { + case color { + Neutral -> "border-neutral border-t-neutral-foreground" + Primary -> "border-primary border-t-primary-foreground" + Secondary -> "border-secondary border-t-secondary-foreground" + Success -> "border-success border-t-success-foreground" + Info -> "border-info border-t-info-foreground" + Warning -> "border-warning border-t-warning-foreground" + Danger -> "border-danger border-t-danger-foreground" + } + |> class +} + +pub fn flat(color: Colors) -> Attribute(a) { + case color { + Neutral -> "border-neutral/20 border-t-neutral" + Primary -> "border-primary/20 border-t-primary" + Secondary -> "border-secondary/20 border-t-secondary" + Success -> "border-success/20 border-t-success" + Info -> "border-info/20 border-t-info" + Warning -> "border-warning/20 border-t-warning" + Danger -> "border-danger/20 border-t-danger" + } + |> class +} + +pub fn light(color: Colors) -> Attribute(a) { + case color { + Neutral -> "border-t-neutral" + Primary -> "border-t-primary" + Secondary -> "border-t-secondary" + Success -> "border-t-success" + Info -> "border-t-info" + Warning -> "border-t-warning" + Danger -> "border-t-danger" + } + |> string.append(" border-transparent") + |> class +} + +pub fn sm() -> Attribute(a) { + class("w-8 h-8 border-4") +} + +pub fn md() -> Attribute(a) { + class("w-12 h-12 border-[6px]") +} + +pub fn lg() -> Attribute(a) { + class("w-16 h-16 border-8") +} diff --git a/app/src/gleez_ui.gleam b/app/src/gleez_ui.gleam index 76d9bbd..c3ae98f 100644 --- a/app/src/gleez_ui.gleam +++ b/app/src/gleez_ui.gleam @@ -22,7 +22,7 @@ pub fn main() { fn init(_) -> #(Model, Effect(Msg)) { #( - Model(page: route.Home, repo: None), + Model(page: route.Spinner, repo: None), batch([fetch_stargazers_count(), modem.init(on_url_change), on_load()]), ) } @@ -47,6 +47,7 @@ fn on_url_change(uri: Uri) -> Msg { ["docs", "components", "switch"] -> OnRouteChange(route.Switch) ["docs", "components", "kbd"] -> OnRouteChange(route.Kbd) ["docs", "components", "checkbox"] -> OnRouteChange(route.Checkbox) + ["docs", "components", "spinner"] -> OnRouteChange(route.Spinner) _ -> OnRouteChange(route.Home) } } @@ -135,6 +136,7 @@ fn with_aside(model: Model) -> Element(Msg) { route.Switch -> page.switch() route.Kbd -> page.kbd() route.Checkbox -> page.checkbox() + route.Spinner -> page.spinner() _ -> page.home() }, ]), diff --git a/app/src/model/route.gleam b/app/src/model/route.gleam index 689872b..8f1bf47 100644 --- a/app/src/model/route.gleam +++ b/app/src/model/route.gleam @@ -23,6 +23,7 @@ pub type Pages { Switch Kbd Checkbox + Spinner } pub const home = "/" @@ -65,6 +66,8 @@ pub const kbd = "/docs/components/kbd" pub const checkbox = "/docs/components/checkbox" +pub const spinner = "/docs/components/spinner" + pub type Page { Page(path: String, sub_pages: List(Page)) } @@ -87,6 +90,7 @@ pub fn pages() -> List(Page) { Page(switch, []), Page(kbd, []), Page(checkbox, []), + Page(spinner, []), ] |> sort_pages, ), @@ -114,6 +118,7 @@ pub fn to_path(page: Pages) -> String { Switch -> switch Kbd -> kbd Checkbox -> checkbox + Spinner -> spinner } } diff --git a/app/src/pages/demo/demo.gleam b/app/src/pages/demo/demo.gleam index 6f7ea12..527df58 100644 --- a/app/src/pages/demo/demo.gleam +++ b/app/src/pages/demo/demo.gleam @@ -1,18 +1,12 @@ -import components/ui/checkbox.{checkbox} -import lustre/attribute.{checked, class, disabled} -import lustre/element.{type Element, text} +import components/ui/spinner.{spinner} +import lustre/attribute.{class} +import lustre/element.{type Element} import lustre/element/html.{div} pub fn demo() -> Element(a) { div([class("flex flex-wrap gap-4 items-center justify-center w-full")], [ - checkbox( - [ - checkbox.solid(checkbox.Neutral), - checkbox.md(), - checked(True), - disabled(True), - ], - [text("Disabled")], - ), + spinner([spinner.solid(spinner.Neutral), spinner.sm()]), + spinner([spinner.solid(spinner.Neutral), spinner.md()]), + spinner([spinner.solid(spinner.Neutral), spinner.lg()]), ]) } diff --git a/app/src/pages/docs/components/spinner/attributes.gleam b/app/src/pages/docs/components/spinner/attributes.gleam new file mode 100644 index 0000000..a7faad2 --- /dev/null +++ b/app/src/pages/docs/components/spinner/attributes.gleam @@ -0,0 +1,39 @@ +import components/ui/spinner.{spinner} +import lustre/element.{type Element} +import pages/docs/sections/section + +pub fn attributes() -> Element(a) { + section.attributes([ + section.attribute( + "Size", + " +- `sm()`: Small Size +- `md()`: Medium Size +- `lg()`: Large Size + ", + [ + spinner([spinner.solid(spinner.Neutral), spinner.sm()]), + spinner([spinner.solid(spinner.Neutral), spinner.md()]), + spinner([spinner.solid(spinner.Neutral), spinner.lg()]), + ], + size_code(), + ), + ]) +} + +fn size_code() -> String { + " +import components/ui/spinner.{spinner} +import lustre/attribute.{class} +import lustre/element.{type Element} +import lustre/element/html.{div} + +pub fn demo() -> Element(a) { + div([class(\"flex flex-wrap gap-4 items-center justify-center w-full\")], [ + spinner([spinner.solid(spinner.Neutral), spinner.sm()]), + spinner([spinner.solid(spinner.Neutral), spinner.md()]), + spinner([spinner.solid(spinner.Neutral), spinner.lg()]), + ]) +} +" +} diff --git a/app/src/pages/docs/components/spinner/examples.gleam b/app/src/pages/docs/components/spinner/examples.gleam new file mode 100644 index 0000000..65153de --- /dev/null +++ b/app/src/pages/docs/components/spinner/examples.gleam @@ -0,0 +1,39 @@ +import components/ui/spinner.{spinner} +import lustre/attribute.{class} +import lustre/element.{type Element, text} +import lustre/element/html.{div, span} +import pages/docs/sections/section + +pub fn examples() -> Element(a) { + section.examples([ + section.example( + "With Text", + "", + [ + div([class("flex flex-col gap-4 items-center")], [ + spinner([spinner.solid(spinner.Neutral), spinner.md()]), + span([], [text("Loading...")]), + ]), + ], + with_text_code(), + ), + ]) +} + +fn with_text_code() -> String { + " +import components/ui/spinner.{spinner} +import lustre/attribute.{class} +import lustre/element.{type Element, text} +import lustre/element/html.{div, span} + +pub fn demo() -> Element(a) { + div([class(\"flex flex-wrap gap-4 items-center justify-center w-full\")], [ + div([class(\"flex flex-col gap-4 items-center\")], [ + spinner([spinner.solid(spinner.Neutral), spinner.md()]), + span([], [text(\"Loading...\")]), + ]), + ]) +} +" +} diff --git a/app/src/pages/docs/components/spinner/spinner.gleam b/app/src/pages/docs/components/spinner/spinner.gleam new file mode 100644 index 0000000..8af6f4f --- /dev/null +++ b/app/src/pages/docs/components/spinner/spinner.gleam @@ -0,0 +1,18 @@ +import components/prose.{prose} +import lustre/element.{type Element} +import pages/docs/components/spinner/attributes.{attributes} +import pages/docs/components/spinner/examples.{examples} +import pages/docs/components/spinner/variants.{variants} +import pages/docs/sections/section + +pub fn docs() -> Element(a) { + prose([], [ + section.intro( + "Spinner", + "Spinners provide a visual cue that an action is processing awaiting a course of change or a result.",), + section.installation("gleam run -m gleez add spinner"), + variants(), + attributes(), + examples(), + ]) +} diff --git a/app/src/pages/docs/components/spinner/variants.gleam b/app/src/pages/docs/components/spinner/variants.gleam new file mode 100644 index 0000000..5bf382a --- /dev/null +++ b/app/src/pages/docs/components/spinner/variants.gleam @@ -0,0 +1,113 @@ +import components/ui/spinner.{spinner} +import lustre/element.{type Element} +import pages/docs/sections/section + +pub fn variants() -> Element(a) { + section.variants([ + section.variant( + "Solid", + "", + [ + spinner([spinner.solid(spinner.Neutral), spinner.md()]), + spinner([spinner.solid(spinner.Primary), spinner.md()]), + spinner([spinner.solid(spinner.Secondary), spinner.md()]), + spinner([spinner.solid(spinner.Success), spinner.md()]), + spinner([spinner.solid(spinner.Info), spinner.md()]), + spinner([spinner.solid(spinner.Warning), spinner.md()]), + spinner([spinner.solid(spinner.Danger), spinner.md()]), + ], + solid_code(), + ), + section.variant( + "Flat", + "", + [ + spinner([spinner.flat(spinner.Neutral), spinner.md()]), + spinner([spinner.flat(spinner.Primary), spinner.md()]), + spinner([spinner.flat(spinner.Secondary), spinner.md()]), + spinner([spinner.flat(spinner.Success), spinner.md()]), + spinner([spinner.flat(spinner.Info), spinner.md()]), + spinner([spinner.flat(spinner.Warning), spinner.md()]), + spinner([spinner.flat(spinner.Danger), spinner.md()]), + ], + flat_code(), + ), + section.variant( + "light", + "", + [ + spinner([spinner.light(spinner.Neutral), spinner.md()]), + spinner([spinner.light(spinner.Primary), spinner.md()]), + spinner([spinner.light(spinner.Secondary), spinner.md()]), + spinner([spinner.light(spinner.Success), spinner.md()]), + spinner([spinner.light(spinner.Info), spinner.md()]), + spinner([spinner.light(spinner.Warning), spinner.md()]), + spinner([spinner.light(spinner.Danger), spinner.md()]), + ], + light_code(), + ), + ]) +} + +fn solid_code() -> String { + " +import components/ui/spinner.{spinner} +import lustre/attribute.{class} +import lustre/element.{type Element} +import lustre/element/html.{div} + +pub fn demo() -> Element(a) { + div([class(\"flex flex-wrap gap-4 items-center justify-center w-full\")], [ + spinner([spinner.solid(spinner.Neutral), spinner.md()]), + spinner([spinner.solid(spinner.Primary), spinner.md()]), + spinner([spinner.solid(spinner.Secondary), spinner.md()]), + spinner([spinner.solid(spinner.Success), spinner.md()]), + spinner([spinner.solid(spinner.Info), spinner.md()]), + spinner([spinner.solid(spinner.Warning), spinner.md()]), + spinner([spinner.solid(spinner.Danger), spinner.md()]), + ]) +} +" +} + +fn flat_code() -> String { + " +import components/ui/spinner.{spinner} +import lustre/attribute.{class} +import lustre/element.{type Element} +import lustre/element/html.{div} + +pub fn demo() -> Element(a) { + div([class(\"flex flex-wrap gap-4 items-center justify-center w-full\")], [ + spinner([spinner.flat(spinner.Neutral), spinner.md()]), + spinner([spinner.flat(spinner.Primary), spinner.md()]), + spinner([spinner.flat(spinner.Secondary), spinner.md()]), + spinner([spinner.flat(spinner.Success), spinner.md()]), + spinner([spinner.flat(spinner.Info), spinner.md()]), + spinner([spinner.flat(spinner.Warning), spinner.md()]), + spinner([spinner.flat(spinner.Danger), spinner.md()]), + ]) +} +" +} + +fn light_code() -> String { + " +import components/ui/spinner.{spinner} +import lustre/attribute.{class} +import lustre/element.{type Element} +import lustre/element/html.{div} + +pub fn demo() -> Element(a) { + div([class(\"flex flex-wrap gap-4 items-center justify-center w-full\")], [ + spinner([spinner.light(spinner.Neutral), spinner.md()]), + spinner([spinner.light(spinner.Primary), spinner.md()]), + spinner([spinner.light(spinner.Secondary), spinner.md()]), + spinner([spinner.light(spinner.Success), spinner.md()]), + spinner([spinner.light(spinner.Info), spinner.md()]), + spinner([spinner.light(spinner.Warning), spinner.md()]), + spinner([spinner.light(spinner.Danger), spinner.md()]), + ]) +} +" +} diff --git a/app/src/pages/page.gleam b/app/src/pages/page.gleam index d91411b..e8c2f1e 100644 --- a/app/src/pages/page.gleam +++ b/app/src/pages/page.gleam @@ -9,6 +9,7 @@ import pages/docs/components/chip/chip import pages/docs/components/divider/divider import pages/docs/components/input/input import pages/docs/components/kbd/kbd +import pages/docs/components/spinner/spinner import pages/docs/components/link/link import pages/docs/components/switch/switch import pages/docs/components/tooltip/tooltip @@ -54,3 +55,5 @@ pub const switch = switch.docs pub const kbd = kbd.docs pub const checkbox = checkbox.docs + +pub const spinner = spinner.docs From 241abfa542f97e1950a646411027e32f1b4f94f4 Mon Sep 17 00:00:00 2001 From: mahcodes Date: Fri, 10 May 2024 11:05:06 +0300 Subject: [PATCH 04/17] docs(spinner): use flat variant for attributes and examples section --- app/src/gleez_ui.gleam | 2 +- .../pages/docs/components/spinner/attributes.gleam | 12 ++++++------ app/src/pages/docs/components/spinner/examples.gleam | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/app/src/gleez_ui.gleam b/app/src/gleez_ui.gleam index c3ae98f..cf3bdcc 100644 --- a/app/src/gleez_ui.gleam +++ b/app/src/gleez_ui.gleam @@ -22,7 +22,7 @@ pub fn main() { fn init(_) -> #(Model, Effect(Msg)) { #( - Model(page: route.Spinner, repo: None), + Model(page: route.Home, repo: None), batch([fetch_stargazers_count(), modem.init(on_url_change), on_load()]), ) } diff --git a/app/src/pages/docs/components/spinner/attributes.gleam b/app/src/pages/docs/components/spinner/attributes.gleam index a7faad2..b5206f1 100644 --- a/app/src/pages/docs/components/spinner/attributes.gleam +++ b/app/src/pages/docs/components/spinner/attributes.gleam @@ -12,9 +12,9 @@ pub fn attributes() -> Element(a) { - `lg()`: Large Size ", [ - spinner([spinner.solid(spinner.Neutral), spinner.sm()]), - spinner([spinner.solid(spinner.Neutral), spinner.md()]), - spinner([spinner.solid(spinner.Neutral), spinner.lg()]), + spinner([spinner.flat(spinner.Neutral), spinner.sm()]), + spinner([spinner.flat(spinner.Neutral), spinner.md()]), + spinner([spinner.flat(spinner.Neutral), spinner.lg()]), ], size_code(), ), @@ -30,9 +30,9 @@ import lustre/element/html.{div} pub fn demo() -> Element(a) { div([class(\"flex flex-wrap gap-4 items-center justify-center w-full\")], [ - spinner([spinner.solid(spinner.Neutral), spinner.sm()]), - spinner([spinner.solid(spinner.Neutral), spinner.md()]), - spinner([spinner.solid(spinner.Neutral), spinner.lg()]), + spinner([spinner.flat(spinner.Neutral), spinner.sm()]), + spinner([spinner.flat(spinner.Neutral), spinner.md()]), + spinner([spinner.flat(spinner.Neutral), spinner.lg()]), ]) } " diff --git a/app/src/pages/docs/components/spinner/examples.gleam b/app/src/pages/docs/components/spinner/examples.gleam index 65153de..045f626 100644 --- a/app/src/pages/docs/components/spinner/examples.gleam +++ b/app/src/pages/docs/components/spinner/examples.gleam @@ -11,7 +11,7 @@ pub fn examples() -> Element(a) { "", [ div([class("flex flex-col gap-4 items-center")], [ - spinner([spinner.solid(spinner.Neutral), spinner.md()]), + spinner([spinner.flat(spinner.Neutral), spinner.md()]), span([], [text("Loading...")]), ]), ], @@ -30,7 +30,7 @@ import lustre/element/html.{div, span} pub fn demo() -> Element(a) { div([class(\"flex flex-wrap gap-4 items-center justify-center w-full\")], [ div([class(\"flex flex-col gap-4 items-center\")], [ - spinner([spinner.solid(spinner.Neutral), spinner.md()]), + spinner([spinner.flat(spinner.Neutral), spinner.md()]), span([], [text(\"Loading...\")]), ]), ]) From 5a35f7131910baed89ea739d74d40d0695a1ffe3 Mon Sep 17 00:00:00 2001 From: mahcodes Date: Fri, 10 May 2024 12:49:30 +0300 Subject: [PATCH 05/17] feat(divider)!: rework divider BREAKING CHANGE: - remove variants: `vertical`, `horizontal` - new variants: `solid`, `dashed`, `dotted` - new attributes: `vertical`, `horizontal` - new attributes: `sm`, `md`, `lg` --- app/src/components/header/actions.gleam | 2 +- app/src/components/ui/divider.gleam | 51 +++- app/src/gleez_ui.gleam | 2 +- app/src/pages/demo/demo.gleam | 10 +- .../docs/components/divider/attributes.gleam | 115 +++++++++ .../docs/components/divider/divider.gleam | 2 + .../docs/components/divider/variants.gleam | 241 ++++++++++++------ app/src/pages/docs/guide/colors/colors.gleam | 2 +- .../guide/installation/installation.gleam | 7 +- app/src/pages/docs/guide/intro/intro.gleam | 28 +- app/src/pages/docs/sections/attributes.gleam | 2 +- app/src/pages/docs/sections/examples.gleam | 2 +- .../pages/docs/sections/installation.gleam | 7 +- app/src/pages/docs/sections/variants.gleam | 2 +- 14 files changed, 368 insertions(+), 105 deletions(-) create mode 100644 app/src/pages/docs/components/divider/attributes.gleam diff --git a/app/src/components/header/actions.gleam b/app/src/components/header/actions.gleam index baad2aa..00096fa 100644 --- a/app/src/components/header/actions.gleam +++ b/app/src/components/header/actions.gleam @@ -30,7 +30,7 @@ pub fn actions() -> Element(a) { ], ), ), - divider([divider.vertical(divider.Neutral)]), + divider([divider.solid(divider.Neutral), divider.sm(), divider.vertical()]), tooltip( [ tooltip.flat(tooltip.Neutral), diff --git a/app/src/components/ui/divider.gleam b/app/src/components/ui/divider.gleam index c074569..8d46de8 100644 --- a/app/src/components/ui/divider.gleam +++ b/app/src/components/ui/divider.gleam @@ -17,35 +17,62 @@ pub fn divider(attributes: List(Attribute(a))) -> Element(a) { div( [ role("separator"), - class("shrink-0 border-none self-stretch bg-opacity-35 rounded-full"), + class("shrink-0 self-stretch bg-opacity-35"), ..attributes ], [], ) } -pub fn vertical(color: Colors) -> Attribute(a) { +pub fn solid(color: Colors) -> Attribute(a) { color |> paint - |> string.append(" h-full w-[1px]") + |> string.append(" border-solid") |> class } -pub fn horizontal(color: Colors) -> Attribute(a) { +pub fn dashed(color: Colors) -> Attribute(a) { color |> paint - |> string.append(" w-full h-[1px]") + |> string.append(" border-dashed") |> class } +pub fn dotted(color: Colors) -> Attribute(a) { + color + |> paint + |> string.append(" border-dotted") + |> class +} + +pub fn vertical() -> Attribute(a) { + class("h-full w-0 border-y-0 border-l-0") +} + +pub fn horizontal() -> Attribute(a) { + class("w-full h-0 border-x-0 border-t-0") +} + +pub fn sm() -> Attribute(a) { + class("border") +} + +pub fn md() -> Attribute(a) { + class("border-2") +} + +pub fn lg() -> Attribute(a) { + class("border-4") +} + fn paint(color: Colors) -> String { case color { - Neutral -> "bg-neutral" - Primary -> "bg-primary" - Secondary -> "bg-secondary" - Success -> "bg-success" - Info -> "bg-info" - Warning -> "bg-warning" - Danger -> "bg-danger" + Neutral -> "border-neutral" + Primary -> "border-primary" + Secondary -> "border-secondary" + Success -> "border-success" + Info -> "border-info" + Warning -> "border-warning" + Danger -> "border-danger" } } diff --git a/app/src/gleez_ui.gleam b/app/src/gleez_ui.gleam index cf3bdcc..95a75fa 100644 --- a/app/src/gleez_ui.gleam +++ b/app/src/gleez_ui.gleam @@ -22,7 +22,7 @@ pub fn main() { fn init(_) -> #(Model, Effect(Msg)) { #( - Model(page: route.Home, repo: None), + Model(page: route.Demo, repo: None), batch([fetch_stargazers_count(), modem.init(on_url_change), on_load()]), ) } diff --git a/app/src/pages/demo/demo.gleam b/app/src/pages/demo/demo.gleam index 527df58..e4c356a 100644 --- a/app/src/pages/demo/demo.gleam +++ b/app/src/pages/demo/demo.gleam @@ -1,12 +1,12 @@ -import components/ui/spinner.{spinner} +import components/ui/divider.{divider} import lustre/attribute.{class} import lustre/element.{type Element} import lustre/element/html.{div} pub fn demo() -> Element(a) { - div([class("flex flex-wrap gap-4 items-center justify-center w-full")], [ - spinner([spinner.solid(spinner.Neutral), spinner.sm()]), - spinner([spinner.solid(spinner.Neutral), spinner.md()]), - spinner([spinner.solid(spinner.Neutral), spinner.lg()]), + div([class("flex flex-col items-center gap-8 w-full")], [ + divider([divider.solid(divider.Neutral), divider.horizontal(), divider.sm()]), + divider([divider.solid(divider.Neutral), divider.horizontal(), divider.md()]), + divider([divider.solid(divider.Neutral), divider.horizontal(), divider.lg()]), ]) } diff --git a/app/src/pages/docs/components/divider/attributes.gleam b/app/src/pages/docs/components/divider/attributes.gleam new file mode 100644 index 0000000..b6b70f1 --- /dev/null +++ b/app/src/pages/docs/components/divider/attributes.gleam @@ -0,0 +1,115 @@ +import components/ui/divider.{divider} +import lustre/attribute.{class} +import lustre/element.{type Element} +import lustre/element/html.{div} +import pages/docs/sections/section + +pub fn attributes() -> Element(a) { + section.attributes([ + section.attribute( + "Horizontal", + " +- `horizontal()`: Horizontal line + ", + [ + divider([ + divider.solid(divider.Neutral), + divider.horizontal(), + divider.md(), + ]), + ], + horizontal_code(), + ), + section.attribute( + "Vertical", + " +- `vertical()`: Vertical line + ", + [ + div([class("h-12")], [ + divider([ + divider.solid(divider.Neutral), + divider.vertical(), + divider.md(), + ]), + ]), + ], + vertical_code(), + ), + section.attribute( + "Size", + " +- `sm()`: Small Size +- `md()`: Medium Size +- `lg()`: Large Size + ", + [ + div([class("flex flex-col items-center gap-8 w-full")], [ + divider([ + divider.solid(divider.Neutral), + divider.horizontal(), + divider.sm(), + ]), + divider([ + divider.solid(divider.Neutral), + divider.horizontal(), + divider.md(), + ]), + divider([ + divider.solid(divider.Neutral), + divider.horizontal(), + divider.lg(), + ]), + ]), + ], + size_code(), + ), + ]) +} + +fn horizontal_code() -> String { + " +import components/ui/divider.{divider} +import lustre/attribute.{class} +import lustre/element.{type Element} +import lustre/element/html.{div} + +pub fn demo() -> Element(a) { + div([class(\"flex flex-col items-center gap-8 w-full\")], [ + divider([divider.solid(divider.Neutral), divider.horizontal(), divider.md()]), + ]) +} +" +} + +fn vertical_code() -> String { + " +import components/ui/divider.{divider} +import lustre/attribute.{class} +import lustre/element.{type Element} +import lustre/element/html.{div} + +pub fn demo() -> Element(a) { + div([class(\"flex items-center justify-center gap-8 w-full h-12\")], [ + divider([divider.solid(divider.Neutral), divider.vertical(), divider.md()]), + ]) +} +" +} + +fn size_code() -> String { + " +import components/ui/divider.{divider} +import lustre/attribute.{class} +import lustre/element.{type Element} +import lustre/element/html.{div} + +pub fn demo() -> Element(a) { + div([class(\"flex flex-col items-center gap-8 w-full\")], [ + divider([divider.solid(divider.Neutral), divider.horizontal(), divider.sm()]), + divider([divider.solid(divider.Neutral), divider.horizontal(), divider.md()]), + divider([divider.solid(divider.Neutral), divider.horizontal(), divider.lg()]), + ]) +} +" +} diff --git a/app/src/pages/docs/components/divider/divider.gleam b/app/src/pages/docs/components/divider/divider.gleam index bfdf132..2e28933 100644 --- a/app/src/pages/docs/components/divider/divider.gleam +++ b/app/src/pages/docs/components/divider/divider.gleam @@ -1,6 +1,7 @@ import components/prose.{prose} import lustre/element.{type Element} import pages/docs/components/divider/variants.{variants} +import pages/docs/components/divider/attributes.{attributes} import pages/docs/sections/section pub fn docs() -> Element(a) { @@ -11,5 +12,6 @@ pub fn docs() -> Element(a) { ), section.installation("gleam run -m gleez add divider"), variants(), + attributes(), ]) } diff --git a/app/src/pages/docs/components/divider/variants.gleam b/app/src/pages/docs/components/divider/variants.gleam index e410113..fd5e700 100644 --- a/app/src/pages/docs/components/divider/variants.gleam +++ b/app/src/pages/docs/components/divider/variants.gleam @@ -1,115 +1,204 @@ import components/ui/divider.{divider} import lustre/attribute.{class} -import lustre/element.{type Element, text} -import lustre/element/html.{div, p} +import lustre/element.{type Element} +import lustre/element/html.{div} import pages/docs/sections/section pub fn variants() -> Element(a) { section.variants([ section.variant( - "Horizontal", + "Solid", "", [ - div([class("flex flex-col items-center gap-2 w-full")], [ - p([], [text("Neutral")]), - divider([divider.horizontal(divider.Neutral)]), - p([], [text("Primary")]), - divider([divider.horizontal(divider.Primary)]), - p([], [text("Secondary")]), - divider([divider.horizontal(divider.Secondary)]), - p([], [text("Success")]), - divider([divider.horizontal(divider.Success)]), - p([], [text("Info")]), - divider([divider.horizontal(divider.Info)]), - p([], [text("Warning")]), - divider([divider.horizontal(divider.Warning)]), - p([], [text("Danger")]), - divider([divider.horizontal(divider.Danger)]), + div([class("flex flex-col items-center gap-8 w-full")], [ + divider([ + divider.solid(divider.Neutral), + divider.horizontal(), + divider.md(), + ]), + divider([ + divider.solid(divider.Primary), + divider.horizontal(), + divider.md(), + ]), + divider([ + divider.solid(divider.Secondary), + divider.horizontal(), + divider.md(), + ]), + divider([ + divider.solid(divider.Success), + divider.horizontal(), + divider.md(), + ]), + divider([ + divider.solid(divider.Info), + divider.horizontal(), + divider.md(), + ]), + divider([ + divider.solid(divider.Warning), + divider.horizontal(), + divider.md(), + ]), + divider([ + divider.solid(divider.Danger), + divider.horizontal(), + divider.md(), + ]), ]), ], - horizontal_code(), + solid_code(), ), section.variant( - "Vertical", + "Dashed", "", [ - div([class("flex items-center gap-4 h-6")], [ - p([], [text("Neutral")]), - divider([divider.vertical(divider.Neutral)]), - p([], [text("Primary")]), - divider([divider.vertical(divider.Primary)]), - p([], [text("Secondary")]), - divider([divider.vertical(divider.Secondary)]), - p([], [text("Success")]), - divider([divider.vertical(divider.Success)]), - p([], [text("Info")]), - divider([divider.vertical(divider.Info)]), - p([], [text("Warning")]), - divider([divider.vertical(divider.Warning)]), - p([], [text("Danger")]), - divider([divider.vertical(divider.Danger)]), + div([class("flex flex-col items-center gap-8 w-full")], [ + divider([ + divider.dashed(divider.Neutral), + divider.horizontal(), + divider.md(), + ]), + divider([ + divider.dashed(divider.Primary), + divider.horizontal(), + divider.md(), + ]), + divider([ + divider.dashed(divider.Secondary), + divider.horizontal(), + divider.md(), + ]), + divider([ + divider.dashed(divider.Success), + divider.horizontal(), + divider.md(), + ]), + divider([ + divider.dashed(divider.Info), + divider.horizontal(), + divider.md(), + ]), + divider([ + divider.dashed(divider.Warning), + divider.horizontal(), + divider.md(), + ]), + divider([ + divider.dashed(divider.Danger), + divider.horizontal(), + divider.md(), + ]), ]), ], - vertical_code(), + dashed_code(), ), + section.variant( + "Dotted", + "", + [ + div([class("flex flex-col items-center gap-8 w-full")], [ + divider([ + divider.dotted(divider.Neutral), + divider.horizontal(), + divider.md(), + ]), + divider([ + divider.dotted(divider.Primary), + divider.horizontal(), + divider.md(), + ]), + divider([ + divider.dotted(divider.Secondary), + divider.horizontal(), + divider.md(), + ]), + divider([ + divider.dotted(divider.Success), + divider.horizontal(), + divider.md(), + ]), + divider([ + divider.dotted(divider.Info), + divider.horizontal(), + divider.md(), + ]), + divider([ + divider.dotted(divider.Warning), + divider.horizontal(), + divider.md(), + ]), + divider([ + divider.dotted(divider.Danger), + divider.horizontal(), + divider.md(), + ]), + ]), + ], + dotted_code(), + ), + ]) +} + +fn solid_code() -> String { + " +import components/ui/divider.{divider} +import lustre/attribute.{class} +import lustre/element.{type Element} +import lustre/element/html.{div} + +pub fn demo() -> Element(a) { + div([class(\"flex flex-col items-center gap-8 w-full\")], [ + divider([divider.solid(divider.Neutral), divider.horizontal(), divider.md()]), + divider([divider.solid(divider.Primary), divider.horizontal(), divider.md()]), + divider([divider.solid(divider.Secondary), divider.horizontal(), divider.md()]), + divider([divider.solid(divider.Success), divider.horizontal(), divider.md()]), + divider([divider.solid(divider.Info), divider.horizontal(), divider.md()]), + divider([divider.solid(divider.Warning), divider.horizontal(), divider.md()]), + divider([divider.solid(divider.Danger), divider.horizontal(), divider.md()]), ]) } +" +} -fn horizontal_code() -> String { +fn dashed_code() -> String { " import components/ui/divider.{divider} import lustre/attribute.{class} -import lustre/element.{type Element, text} -import lustre/element/html.{div, p} +import lustre/element.{type Element} +import lustre/element/html.{div} pub fn demo() -> Element(a) { - div([class(\"grid grid-cols-3 gap-4 w-full\")], [ - div([class(\"flex items-center gap-4 h-6\")], [ - p([], [text(\"Neutral\")]), - divider([divider.horizontal(divider.Neutral)]), - p([], [text(\"Primary\")]), - divider([divider.horizontal(divider.Primary)]), - p([], [text(\"Secondary\")]), - divider([divider.horizontal(divider.Secondary)]), - p([], [text(\"Success\")]), - divider([divider.horizontal(divider.Success)]), - p([], [text(\"Info\")]), - divider([divider.horizontal(divider.Info)]), - p([], [text(\"Warning\")]), - divider([divider.horizontal(divider.Warning)]), - p([], [text(\"Danger\")]), - divider([divider.horizontal(divider.Danger)]), - ]), + div([class(\"flex flex-col items-center gap-8 w-full\")], [ + divider([divider.dashed(divider.Neutral), divider.horizontal(), divider.md()]), + divider([divider.dashed(divider.Primary), divider.horizontal(), divider.md()]), + divider([divider.dashed(divider.Secondary), divider.horizontal(), divider.md()]), + divider([divider.dashed(divider.Success), divider.horizontal(), divider.md()]), + divider([divider.dashed(divider.Info), divider.horizontal(), divider.md()]), + divider([divider.dashed(divider.Warning), divider.horizontal(), divider.md()]), + divider([divider.dashed(divider.Danger), divider.horizontal(), divider.md()]), ]) } " } -fn vertical_code() -> String { +fn dotted_code() -> String { " import components/ui/divider.{divider} import lustre/attribute.{class} -import lustre/element.{type Element, text} -import lustre/element/html.{div, p} +import lustre/element.{type Element} +import lustre/element/html.{div} pub fn demo() -> Element(a) { - div([class(\"grid grid-cols-3 gap-4 w-full\")], [ - div([class(\"flex items-center gap-4 h-6\")], [ - p([], [text(\"Neutral\")]), - divider([divider.vertical(divider.Neutral)]), - p([], [text(\"Primary\")]), - divider([divider.vertical(divider.Primary)]), - p([], [text(\"Secondary\")]), - divider([divider.vertical(divider.Secondary)]), - p([], [text(\"Success\")]), - divider([divider.vertical(divider.Success)]), - p([], [text(\"Info\")]), - divider([divider.vertical(divider.Info)]), - p([], [text(\"Warning\")]), - divider([divider.vertical(divider.Warning)]), - p([], [text(\"Danger\")]), - divider([divider.vertical(divider.Danger)]), - ]), + div([class(\"flex flex-col items-center gap-8 w-full\")], [ + divider([divider.dotted(divider.Neutral), divider.horizontal(), divider.md()]), + divider([divider.dotted(divider.Primary), divider.horizontal(), divider.md()]), + divider([divider.dotted(divider.Secondary), divider.horizontal(), divider.md()]), + divider([divider.dotted(divider.Success), divider.horizontal(), divider.md()]), + divider([divider.dotted(divider.Info), divider.horizontal(), divider.md()]), + divider([divider.dotted(divider.Warning), divider.horizontal(), divider.md()]), + divider([divider.dotted(divider.Danger), divider.horizontal(), divider.md()]), ]) } " diff --git a/app/src/pages/docs/guide/colors/colors.gleam b/app/src/pages/docs/guide/colors/colors.gleam index c16afff..eabf092 100644 --- a/app/src/pages/docs/guide/colors/colors.gleam +++ b/app/src/pages/docs/guide/colors/colors.gleam @@ -11,7 +11,7 @@ import lustre/ui/icon pub fn docs() -> Element(a) { prose([], [ h1([], [text("Colors")]), - divider([divider.horizontal(divider.Neutral)]), + divider([divider.solid(divider.Neutral), divider.horizontal(), divider.sm()]), p([], [ text("Gleez"), code([], [text("Colors")]), diff --git a/app/src/pages/docs/guide/installation/installation.gleam b/app/src/pages/docs/guide/installation/installation.gleam index af419c4..1457ff5 100644 --- a/app/src/pages/docs/guide/installation/installation.gleam +++ b/app/src/pages/docs/guide/installation/installation.gleam @@ -9,7 +9,12 @@ import lustre/element/html.{h1, p} pub fn docs() -> Element(a) { prose([], [ h1([], [text("Installation")]), - divider([class("mb-6"), divider.horizontal(divider.Neutral)]), + divider([ + class("mb-6"), + divider.solid(divider.Neutral), + divider.horizontal(), + divider.sm(), + ]), " As mentioned earlier, this is **NOT** a component library. Instead, it's a collection of reusable components that you can integrate into your apps. diff --git a/app/src/pages/docs/guide/intro/intro.gleam b/app/src/pages/docs/guide/intro/intro.gleam index 1f2f954..d5a9359 100644 --- a/app/src/pages/docs/guide/intro/intro.gleam +++ b/app/src/pages/docs/guide/intro/intro.gleam @@ -15,7 +15,12 @@ import model/repo.{type Repo} fn faq() -> Element(a) { fragment([ h2([], [text("FAQ")]), - divider([class("mb-6"), divider.horizontal(divider.Neutral)]), + divider([ + class("mb-6"), + divider.solid(divider.Neutral), + divider.horizontal(), + divider.sm(), + ]), details([], [ summary([], [text("What is the origin of the name \"Gleez\"?")]), p([], [ @@ -57,7 +62,12 @@ fn fun_fact(repo: Option(Repo)) -> Element(a) { Some(r) -> div([], [ h2([], [text("Fun Fact")]), - divider([class("mb-6"), divider.horizontal(divider.Neutral)]), + divider([ + class("mb-6"), + divider.solid(divider.Neutral), + divider.horizontal(), + divider.sm(), + ]), p([class("flex items-center gap-2")], [ text("You can bump up our "), text(int.to_string(r.stargazers_count)), @@ -78,7 +88,12 @@ fn acknowledgments() -> Element(a) { fragment([ h2([], [text("Acknowledgments")]), - divider([class("mb-6"), divider.horizontal(divider.Neutral)]), + divider([ + class("mb-6"), + divider.solid(divider.Neutral), + divider.horizontal(), + divider.sm(), + ]), ul([], [ li([], [ a([href("https://github.com/lustre-labs/ui"), ..link_atts], [ @@ -138,7 +153,12 @@ pub fn docs(repo: Option(Repo)) -> Element(a) { text(" ✨"), ]), h2([], [text("Introduction")]), - divider([class("mb-6"), divider.horizontal(divider.Neutral)]), + divider([ + class("mb-6"), + divider.solid(divider.Neutral), + divider.horizontal(), + divider.sm(), + ]), shadcn(), fun_fact(repo), faq(), diff --git a/app/src/pages/docs/sections/attributes.gleam b/app/src/pages/docs/sections/attributes.gleam index 8d780bf..862f407 100644 --- a/app/src/pages/docs/sections/attributes.gleam +++ b/app/src/pages/docs/sections/attributes.gleam @@ -7,7 +7,7 @@ import lustre/element/html.{div, h2, h3, p, text} pub fn attributes(attributes: List(Element(a))) -> Element(a) { div([], [ h2([], [text("Attributes")]), - divider([divider.horizontal(divider.Neutral)]), + divider([divider.solid(divider.Neutral), divider.horizontal(), divider.sm()]), ..attributes ]) } diff --git a/app/src/pages/docs/sections/examples.gleam b/app/src/pages/docs/sections/examples.gleam index ee82858..1d6f5aa 100644 --- a/app/src/pages/docs/sections/examples.gleam +++ b/app/src/pages/docs/sections/examples.gleam @@ -7,7 +7,7 @@ import lustre/element/html.{div, h2, h3, p, text} pub fn examples(examples: List(Element(a))) -> Element(a) { div([], [ h2([], [text("Examples")]), - divider([divider.horizontal(divider.Neutral)]), + divider([divider.solid(divider.Neutral)]), ..examples ]) } diff --git a/app/src/pages/docs/sections/installation.gleam b/app/src/pages/docs/sections/installation.gleam index 9582a8c..11b5dd0 100644 --- a/app/src/pages/docs/sections/installation.gleam +++ b/app/src/pages/docs/sections/installation.gleam @@ -7,7 +7,12 @@ import lustre/element/html.{div, h2, text} pub fn installation(command: String) -> Element(a) { div([], [ h2([], [text("Installation")]), - divider([class("mb-6"), divider.horizontal(divider.Neutral)]), + divider([ + class("mb-6"), + divider.solid(divider.Neutral), + divider.horizontal(), + divider.sm(), + ]), snippet(command, "shell"), ]) } diff --git a/app/src/pages/docs/sections/variants.gleam b/app/src/pages/docs/sections/variants.gleam index 833199d..9fd908d 100644 --- a/app/src/pages/docs/sections/variants.gleam +++ b/app/src/pages/docs/sections/variants.gleam @@ -12,7 +12,7 @@ import model/route pub fn variants(children: List(Element(a))) -> Element(a) { div([], [ h2([], [text("Variants")]), - divider([divider.horizontal(divider.Neutral)]), + divider([divider.solid(divider.Neutral), divider.horizontal(), divider.sm()]), ..children ]) } From b55a1038cf6f424a2c04789012883930e5cc03a0 Mon Sep 17 00:00:00 2001 From: mahcodes Date: Fri, 10 May 2024 12:54:36 +0300 Subject: [PATCH 06/17] fix(spinner): sizes --- app/src/components/ui/spinner.gleam | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/components/ui/spinner.gleam b/app/src/components/ui/spinner.gleam index 2b299e5..6f60f6a 100644 --- a/app/src/components/ui/spinner.gleam +++ b/app/src/components/ui/spinner.gleam @@ -1,6 +1,6 @@ import gleam/string import lustre/attribute.{type Attribute, class} -import lustre/element.{type Element, text} +import lustre/element.{type Element} import lustre/element/html.{div} pub type Colors { @@ -58,13 +58,13 @@ pub fn light(color: Colors) -> Attribute(a) { } pub fn sm() -> Attribute(a) { - class("w-8 h-8 border-4") + class("w-8 h-8 border-2") } pub fn md() -> Attribute(a) { - class("w-12 h-12 border-[6px]") + class("w-10 h-10 border-4") } pub fn lg() -> Attribute(a) { - class("w-16 h-16 border-8") + class("w-12 h-12 border-[6px]") } From 60ee1712551da98fef29ea44fc553be6dbd21c98 Mon Sep 17 00:00:00 2001 From: mahcodes Date: Fri, 10 May 2024 12:56:14 +0300 Subject: [PATCH 07/17] style: format --- app/src/gleez_ui.gleam | 2 +- app/src/pages/docs/components/divider/divider.gleam | 2 +- app/src/pages/docs/components/kbd/kbd.gleam | 3 ++- app/src/pages/docs/components/spinner/spinner.gleam | 3 ++- app/src/pages/page.gleam | 2 +- 5 files changed, 7 insertions(+), 5 deletions(-) diff --git a/app/src/gleez_ui.gleam b/app/src/gleez_ui.gleam index 95a75fa..cf3bdcc 100644 --- a/app/src/gleez_ui.gleam +++ b/app/src/gleez_ui.gleam @@ -22,7 +22,7 @@ pub fn main() { fn init(_) -> #(Model, Effect(Msg)) { #( - Model(page: route.Demo, repo: None), + Model(page: route.Home, repo: None), batch([fetch_stargazers_count(), modem.init(on_url_change), on_load()]), ) } diff --git a/app/src/pages/docs/components/divider/divider.gleam b/app/src/pages/docs/components/divider/divider.gleam index 2e28933..1a22837 100644 --- a/app/src/pages/docs/components/divider/divider.gleam +++ b/app/src/pages/docs/components/divider/divider.gleam @@ -1,7 +1,7 @@ import components/prose.{prose} import lustre/element.{type Element} -import pages/docs/components/divider/variants.{variants} import pages/docs/components/divider/attributes.{attributes} +import pages/docs/components/divider/variants.{variants} import pages/docs/sections/section pub fn docs() -> Element(a) { diff --git a/app/src/pages/docs/components/kbd/kbd.gleam b/app/src/pages/docs/components/kbd/kbd.gleam index 92dddb6..2c6fca5 100644 --- a/app/src/pages/docs/components/kbd/kbd.gleam +++ b/app/src/pages/docs/components/kbd/kbd.gleam @@ -9,7 +9,8 @@ pub fn docs() -> Element(a) { prose([], [ section.intro( "Kbd", - "The keyboard key component exists to show which key or combination of keys performs a given action.",), + "The keyboard key component exists to show which key or combination of keys performs a given action.", + ), section.installation("gleam run -m gleez add kbd"), variants(), attributes(), diff --git a/app/src/pages/docs/components/spinner/spinner.gleam b/app/src/pages/docs/components/spinner/spinner.gleam index 8af6f4f..cb504f3 100644 --- a/app/src/pages/docs/components/spinner/spinner.gleam +++ b/app/src/pages/docs/components/spinner/spinner.gleam @@ -9,7 +9,8 @@ pub fn docs() -> Element(a) { prose([], [ section.intro( "Spinner", - "Spinners provide a visual cue that an action is processing awaiting a course of change or a result.",), + "Spinners provide a visual cue that an action is processing awaiting a course of change or a result.", + ), section.installation("gleam run -m gleez add spinner"), variants(), attributes(), diff --git a/app/src/pages/page.gleam b/app/src/pages/page.gleam index e8c2f1e..7cace48 100644 --- a/app/src/pages/page.gleam +++ b/app/src/pages/page.gleam @@ -9,8 +9,8 @@ import pages/docs/components/chip/chip import pages/docs/components/divider/divider import pages/docs/components/input/input import pages/docs/components/kbd/kbd -import pages/docs/components/spinner/spinner import pages/docs/components/link/link +import pages/docs/components/spinner/spinner import pages/docs/components/switch/switch import pages/docs/components/tooltip/tooltip import pages/docs/guide/colors/colors From 160bfa090e04130c82bc798deac72aad4dfb7d8e Mon Sep 17 00:00:00 2001 From: mahcodes Date: Sat, 11 May 2024 14:58:40 +0300 Subject: [PATCH 08/17] feat: new `skeleton` component --- app/src/components/ui/link.gleam | 1 - app/src/components/ui/skeleton.gleam | 30 +++++++ app/src/gleez_ui.gleam | 2 + app/src/model/route.gleam | 5 ++ app/src/pages/demo/demo.gleam | 36 ++++++-- .../docs/components/skeleton/examples.gleam | 87 +++++++++++++++++++ .../docs/components/skeleton/skeleton.gleam | 17 ++++ .../docs/components/skeleton/variants.gleam | 62 +++++++++++++ app/src/pages/docs/sections/examples.gleam | 2 +- app/src/pages/page.gleam | 3 + 10 files changed, 237 insertions(+), 8 deletions(-) create mode 100644 app/src/components/ui/skeleton.gleam create mode 100644 app/src/pages/docs/components/skeleton/examples.gleam create mode 100644 app/src/pages/docs/components/skeleton/skeleton.gleam create mode 100644 app/src/pages/docs/components/skeleton/variants.gleam diff --git a/app/src/components/ui/link.gleam b/app/src/components/ui/link.gleam index 201fa94..fbdf1bf 100644 --- a/app/src/components/ui/link.gleam +++ b/app/src/components/ui/link.gleam @@ -70,7 +70,6 @@ pub fn link(color: Colors) -> Attribute(a) { Warning -> "text-warning" Danger -> "text-danger" } - |> string.append("") |> class } diff --git a/app/src/components/ui/skeleton.gleam b/app/src/components/ui/skeleton.gleam new file mode 100644 index 0000000..e32545e --- /dev/null +++ b/app/src/components/ui/skeleton.gleam @@ -0,0 +1,30 @@ +import lustre/attribute.{type Attribute, class} +import lustre/element.{type Element} +import lustre/element/html.{div} + +pub type Colors { + Neutral + Primary + Secondary + Success + Info + Warning + Danger +} + +pub fn skeleton(attributes: List(Attribute(a))) -> Element(a) { + div([class("animate-pulse"), ..attributes], []) +} + +pub fn solid(color: Colors) -> Attribute(a) { + case color { + Neutral -> "bg-neutral/50" + Primary -> "bg-primary/50" + Secondary -> "bg-secondary/50" + Success -> "bg-success/50" + Info -> "bg-info/50" + Warning -> "bg-warning/50" + Danger -> "bg-danger/50" + } + |> class +} diff --git a/app/src/gleez_ui.gleam b/app/src/gleez_ui.gleam index cf3bdcc..803d404 100644 --- a/app/src/gleez_ui.gleam +++ b/app/src/gleez_ui.gleam @@ -48,6 +48,7 @@ fn on_url_change(uri: Uri) -> Msg { ["docs", "components", "kbd"] -> OnRouteChange(route.Kbd) ["docs", "components", "checkbox"] -> OnRouteChange(route.Checkbox) ["docs", "components", "spinner"] -> OnRouteChange(route.Spinner) + ["docs", "components", "skeleton"] -> OnRouteChange(route.Skeleton) _ -> OnRouteChange(route.Home) } } @@ -137,6 +138,7 @@ fn with_aside(model: Model) -> Element(Msg) { route.Kbd -> page.kbd() route.Checkbox -> page.checkbox() route.Spinner -> page.spinner() + route.Skeleton -> page.skeleton() _ -> page.home() }, ]), diff --git a/app/src/model/route.gleam b/app/src/model/route.gleam index 8f1bf47..24c5920 100644 --- a/app/src/model/route.gleam +++ b/app/src/model/route.gleam @@ -24,6 +24,7 @@ pub type Pages { Kbd Checkbox Spinner + Skeleton } pub const home = "/" @@ -68,6 +69,8 @@ pub const checkbox = "/docs/components/checkbox" pub const spinner = "/docs/components/spinner" +pub const skeleton = "/docs/components/skeleton" + pub type Page { Page(path: String, sub_pages: List(Page)) } @@ -91,6 +94,7 @@ pub fn pages() -> List(Page) { Page(kbd, []), Page(checkbox, []), Page(spinner, []), + Page(skeleton, []), ] |> sort_pages, ), @@ -119,6 +123,7 @@ pub fn to_path(page: Pages) -> String { Kbd -> kbd Checkbox -> checkbox Spinner -> spinner + Skeleton -> skeleton } } diff --git a/app/src/pages/demo/demo.gleam b/app/src/pages/demo/demo.gleam index e4c356a..afac30d 100644 --- a/app/src/pages/demo/demo.gleam +++ b/app/src/pages/demo/demo.gleam @@ -1,12 +1,36 @@ -import components/ui/divider.{divider} +import components/ui/skeleton.{skeleton} import lustre/attribute.{class} import lustre/element.{type Element} import lustre/element/html.{div} pub fn demo() -> Element(a) { - div([class("flex flex-col items-center gap-8 w-full")], [ - divider([divider.solid(divider.Neutral), divider.horizontal(), divider.sm()]), - divider([divider.solid(divider.Neutral), divider.horizontal(), divider.md()]), - divider([divider.solid(divider.Neutral), divider.horizontal(), divider.lg()]), - ]) + div( + [ + class( + "flex flex-col items-center gap-4 bg-neutral-foreground p-4 rounded-md max-w-xs", + ), + ], + [ + skeleton([ + class("w-full aspect-video rounded-md"), + skeleton.solid(skeleton.Neutral), + ]), + div([class("flex items-center w-full gap-4")], [ + skeleton([ + class("w-12 h-12 rounded-full"), + skeleton.solid(skeleton.Neutral), + ]), + div([class("flex flex-col flex-1 gap-2")], [ + skeleton([ + class("w-full h-4 rounded"), + skeleton.solid(skeleton.Neutral), + ]), + skeleton([ + class("w-2/3 h-4 rounded"), + skeleton.solid(skeleton.Neutral), + ]), + ]), + ]), + ], + ) } diff --git a/app/src/pages/docs/components/skeleton/examples.gleam b/app/src/pages/docs/components/skeleton/examples.gleam new file mode 100644 index 0000000..b34df50 --- /dev/null +++ b/app/src/pages/docs/components/skeleton/examples.gleam @@ -0,0 +1,87 @@ +import components/ui/skeleton.{skeleton} +import lustre/attribute.{class} +import lustre/element.{type Element} +import lustre/element/html.{div} +import pages/docs/sections/section + +pub fn examples() -> Element(a) { + section.examples([ + section.example( + "Card", + "", + [ + div( + [ + class( + "flex flex-col items-center gap-4 bg-neutral-foreground p-4 rounded-md w-full max-w-xs", + ), + ], + [ + skeleton([ + class("w-full aspect-video rounded-md"), + skeleton.solid(skeleton.Neutral), + ]), + div([class("flex items-center w-full gap-4")], [ + skeleton([ + class("w-12 h-12 rounded-full"), + skeleton.solid(skeleton.Neutral), + ]), + div([class("flex flex-col flex-1 gap-2")], [ + skeleton([ + class("w-full h-4 rounded"), + skeleton.solid(skeleton.Neutral), + ]), + skeleton([ + class("w-2/3 h-4 rounded"), + skeleton.solid(skeleton.Neutral), + ]), + ]), + ]), + ], + ), + ], + card_code(), + ), + ]) +} + +fn card_code() -> String { + " +import components/ui/skeleton.{skeleton} +import lustre/attribute.{class} +import lustre/element.{type Element} +import lustre/element/html.{div} + +pub fn demo() -> Element(a) { + div( + [ + class( + \"flex flex-col items-center gap-4 bg-neutral-foreground p-4 rounded-md max-w-xs\", + ), + ], + [ + skeleton([ + class(\"w-full aspect-video rounded-md\"), + skeleton.solid(skeleton.Neutral), + ]), + div([class(\"flex items-center w-full gap-4\")], [ + skeleton([ + class(\"w-12 h-12 rounded-full\"), + skeleton.solid(skeleton.Neutral), + ]), + div([class(\"flex flex-col flex-1 gap-2\")], [ + skeleton([ + class(\"w-full h-4 rounded\"), + skeleton.solid(skeleton.Neutral), + ]), + skeleton([ + class(\"w-2/3 h-4 rounded\"), + skeleton.solid(skeleton.Neutral), + ]), + ]), + ]), + ], + ) +} +" +} diff --git a/app/src/pages/docs/components/skeleton/skeleton.gleam b/app/src/pages/docs/components/skeleton/skeleton.gleam new file mode 100644 index 0000000..7bf599f --- /dev/null +++ b/app/src/pages/docs/components/skeleton/skeleton.gleam @@ -0,0 +1,17 @@ +import components/prose.{prose} +import lustre/element.{type Element} +import pages/docs/components/skeleton/examples.{examples} +import pages/docs/components/skeleton/variants.{variants} +import pages/docs/sections/section + +pub fn docs() -> Element(a) { + prose([], [ + section.intro( + "Skeleton", + "Provide a placeholder while you wait for content to load, or to visualise content that doesn't exist yet.", + ), + section.installation("gleam run -m gleez add skeleton"), + variants(), + examples(), + ]) +} diff --git a/app/src/pages/docs/components/skeleton/variants.gleam b/app/src/pages/docs/components/skeleton/variants.gleam new file mode 100644 index 0000000..7953e82 --- /dev/null +++ b/app/src/pages/docs/components/skeleton/variants.gleam @@ -0,0 +1,62 @@ +import components/ui/skeleton.{skeleton} +import lustre/attribute.{class} +import lustre/element.{type Element} +import pages/docs/sections/section + +pub fn variants() -> Element(a) { + section.variants([ + section.variant( + "Solid", + "", + [ + skeleton([ + class("w-full h-6 rounded-md"), + skeleton.solid(skeleton.Neutral), + ]), + skeleton([ + class("w-full h-6 rounded-md"), + skeleton.solid(skeleton.Primary), + ]), + skeleton([ + class("w-full h-6 rounded-md"), + skeleton.solid(skeleton.Secondary), + ]), + skeleton([ + class("w-full h-6 rounded-md"), + skeleton.solid(skeleton.Success), + ]), + skeleton([class("w-full h-6 rounded-md"), skeleton.solid(skeleton.Info)]), + skeleton([ + class("w-full h-6 rounded-md"), + skeleton.solid(skeleton.Warning), + ]), + skeleton([ + class("w-full h-6 rounded-md"), + skeleton.solid(skeleton.Danger), + ]), + ], + solid_code(), + ), + ]) +} + +fn solid_code() -> String { + " +import components/ui/skeleton.{skeleton} +import lustre/attribute.{class} +import lustre/element.{type Element} +import lustre/element/html.{div} + +pub fn demo() -> Element(a) { + div([class(\"flex flex-col items-center gap-8 w-full\")], [ + skeleton([class(\"w-full h-6 rounded-md\"), skeleton.solid(skeleton.Neutral)]), + skeleton([class(\"w-full h-6 rounded-md\"), skeleton.solid(skeleton.Primary)]), + skeleton([class(\"w-full h-6 rounded-md\"), skeleton.solid(skeleton.Secondary)]), + skeleton([class(\"w-full h-6 rounded-md\"), skeleton.solid(skeleton.Success)]), + skeleton([class(\"w-full h-6 rounded-md\"), skeleton.solid(skeleton.Info)]), + skeleton([class(\"w-full h-6 rounded-md\"), skeleton.solid(skeleton.Warning)]), + skeleton([class(\"w-full h-6 rounded-md\"), skeleton.solid(skeleton.Danger)]), + ]) +} +" +} diff --git a/app/src/pages/docs/sections/examples.gleam b/app/src/pages/docs/sections/examples.gleam index 1d6f5aa..ca42f94 100644 --- a/app/src/pages/docs/sections/examples.gleam +++ b/app/src/pages/docs/sections/examples.gleam @@ -7,7 +7,7 @@ import lustre/element/html.{div, h2, h3, p, text} pub fn examples(examples: List(Element(a))) -> Element(a) { div([], [ h2([], [text("Examples")]), - divider([divider.solid(divider.Neutral)]), + divider([divider.solid(divider.Neutral), divider.horizontal(), divider.sm()]), ..examples ]) } diff --git a/app/src/pages/page.gleam b/app/src/pages/page.gleam index 7cace48..4b914b5 100644 --- a/app/src/pages/page.gleam +++ b/app/src/pages/page.gleam @@ -11,6 +11,7 @@ import pages/docs/components/input/input import pages/docs/components/kbd/kbd import pages/docs/components/link/link import pages/docs/components/spinner/spinner +import pages/docs/components/skeleton/skeleton import pages/docs/components/switch/switch import pages/docs/components/tooltip/tooltip import pages/docs/guide/colors/colors @@ -57,3 +58,5 @@ pub const kbd = kbd.docs pub const checkbox = checkbox.docs pub const spinner = spinner.docs + +pub const skeleton = skeleton.docs From fcc578c6c6a73e68e2247d6b930058534180f704 Mon Sep 17 00:00:00 2001 From: mahcodes Date: Sat, 11 May 2024 17:28:11 +0300 Subject: [PATCH 09/17] fixes --- app/index.html | 4 ++-- app/manifest.toml | 2 +- app/src/assets/js/{ffi.js => ffi.mjs} | 0 app/src/gleez_ui.gleam | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename app/src/assets/js/{ffi.js => ffi.mjs} (100%) diff --git a/app/index.html b/app/index.html index 1ca6c5d..a690f1d 100644 --- a/app/index.html +++ b/app/index.html @@ -23,13 +23,13 @@ - + - + diff --git a/app/manifest.toml b/app/manifest.toml index 5ea0145..e3a697b 100644 --- a/app/manifest.toml +++ b/app/manifest.toml @@ -31,7 +31,7 @@ gleam_stdlib = { version = ">= 0.34.0 and < 2.0.0" } gleescript = { version = ">= 1.0.1 and < 2.0.0" } gleeunit = { version = ">= 1.0.0 and < 2.0.0" } kirala_markdown = { version = ">= 1.0.2 and < 2.0.0" } -lustre = { version = ">= 4.2.0 and < 5.0.0"} +lustre = { version = ">= 4.2.0 and < 5.0.0" } lustre_http = { version = ">= 0.5.2 and < 1.0.0" } lustre_ui = { version = ">= 0.6.0 and < 1.0.0" } modem = { version = ">= 1.0.0 and < 2.0.0" } diff --git a/app/src/assets/js/ffi.js b/app/src/assets/js/ffi.mjs similarity index 100% rename from app/src/assets/js/ffi.js rename to app/src/assets/js/ffi.mjs diff --git a/app/src/gleez_ui.gleam b/app/src/gleez_ui.gleam index 803d404..84e8260 100644 --- a/app/src/gleez_ui.gleam +++ b/app/src/gleez_ui.gleam @@ -61,7 +61,7 @@ pub opaque type Msg { @external(javascript, "./assets/js/highlight/gleam.ffi.mjs", "highlight_all") fn do_highlight_all() -> Nil -@external(javascript, "./assets/js/ffi.js", "attach_all") +@external(javascript, "./assets/js/ffi.mjs", "attach_all") fn do_attach_all() -> Nil fn attach_all() -> Effect(a) { From c43f78040ea7db3787dccee248826230e40469e8 Mon Sep 17 00:00:00 2001 From: mahcodes Date: Sat, 11 May 2024 21:51:30 +0300 Subject: [PATCH 10/17] ssg --- app/src/assets/js/ffi.mjs | 4 ++++ app/src/gleez_ui.gleam | 7 +++++-- app/src/model/route.gleam | 26 ++++++++++++++++++++++++++ app/ssg | 22 ++++++++++++++++++++++ 4 files changed, 57 insertions(+), 2 deletions(-) create mode 100755 app/ssg diff --git a/app/src/assets/js/ffi.mjs b/app/src/assets/js/ffi.mjs index b426965..4958db1 100644 --- a/app/src/assets/js/ffi.mjs +++ b/app/src/assets/js/ffi.mjs @@ -149,3 +149,7 @@ function do_attach_all() { export function attach_all() { window.requestAnimationFrame(do_attach_all); } + +export function pathname() { + return window.location.pathname; +} diff --git a/app/src/gleez_ui.gleam b/app/src/gleez_ui.gleam index 84e8260..37cc92b 100644 --- a/app/src/gleez_ui.gleam +++ b/app/src/gleez_ui.gleam @@ -11,7 +11,7 @@ import lustre/element.{type Element} import lustre/element/html.{div} import lustre_http.{type HttpError} import model/repo.{type Repo, Repo} -import model/route.{type Pages} +import model/route.{type Pages, to_pages} import modem import pages/page @@ -22,7 +22,7 @@ pub fn main() { fn init(_) -> #(Model, Effect(Msg)) { #( - Model(page: route.Home, repo: None), + Model(page: to_pages(pathname()), repo: None), batch([fetch_stargazers_count(), modem.init(on_url_change), on_load()]), ) } @@ -64,6 +64,9 @@ fn do_highlight_all() -> Nil @external(javascript, "./assets/js/ffi.mjs", "attach_all") fn do_attach_all() -> Nil +@external(javascript, "./assets/js/ffi.mjs", "pathname") +fn pathname() -> String + fn attach_all() -> Effect(a) { effect.from(fn(_) { do_attach_all() }) } diff --git a/app/src/model/route.gleam b/app/src/model/route.gleam index 24c5920..f7fc84b 100644 --- a/app/src/model/route.gleam +++ b/app/src/model/route.gleam @@ -127,6 +127,32 @@ pub fn to_path(page: Pages) -> String { } } +pub fn to_pages(path: String) -> Pages { + case path { + p if p == demo -> Demo + p if p == colors -> Colors + p if p == intro -> Intro + p if p == blog -> Blog + p if p == button -> Button + p if p == input -> Input + p if p == link -> Link + p if p == chip -> Chip + p if p == divider -> Divider + p if p == tooltip -> Tooltip + p if p == avatar -> Avatar + p if p == avatar -> Components + p if p == installation -> Installation + p if p == badge -> Badge + p if p == breadcrumbs -> Breadcrumbs + p if p == switch -> Switch + p if p == kbd -> Kbd + p if p == checkbox -> Checkbox + p if p == spinner -> Spinner + p if p == skeleton -> Skeleton + _ -> Home + } +} + pub fn is_active(page: Pages, path: String) -> Bool { to_path(page) == path } diff --git a/app/ssg b/app/ssg new file mode 100755 index 0000000..a548431 --- /dev/null +++ b/app/ssg @@ -0,0 +1,22 @@ +#!/bin/bash + +mkdir -p ./dist/docs/guide/{introduction,installation,colors} +mkdir -p ./dist/docs/components/{button,input,link,chip,divider,tooltip,avatar,badge,breadcrumbs,switch,kbd,checkbox,spinner,skeleton} + +cp ./dist/index.html ./dist/docs/guide/introduction/ +cp ./dist/index.html ./dist/docs/guide/installation/ +cp ./dist/index.html ./dist/docs/guide/colors/ +cp ./dist/index.html ./dist/docs/components/button/ +cp ./dist/index.html ./dist/docs/components/input/ +cp ./dist/index.html ./dist/docs/components/link/ +cp ./dist/index.html ./dist/docs/components/chip/ +cp ./dist/index.html ./dist/docs/components/divider/ +cp ./dist/index.html ./dist/docs/components/tooltip/ +cp ./dist/index.html ./dist/docs/components/avatar/ +cp ./dist/index.html ./dist/docs/components/badge/ +cp ./dist/index.html ./dist/docs/components/breadcrumbs/ +cp ./dist/index.html ./dist/docs/components/switch/ +cp ./dist/index.html ./dist/docs/components/kbd/ +cp ./dist/index.html ./dist/docs/components/checkbox/ +cp ./dist/index.html ./dist/docs/components/spinner/ +cp ./dist/index.html ./dist/docs/components/skeleton/ From 7740fd47713ec45c469c8e0d15f9c1dfb3706dd5 Mon Sep 17 00:00:00 2001 From: mahcodes Date: Sat, 11 May 2024 22:07:00 +0300 Subject: [PATCH 11/17] feat: aside page status --- app/src/components/aside.gleam | 16 +++++++++--- app/src/model/route.gleam | 47 ++++++++++++++++++++++------------ app/ssg | 3 +++ 3 files changed, 47 insertions(+), 19 deletions(-) diff --git a/app/src/components/aside.gleam b/app/src/components/aside.gleam index 9f0bd68..52c8f3a 100644 --- a/app/src/components/aside.gleam +++ b/app/src/components/aside.gleam @@ -1,8 +1,9 @@ +import components/ui/chip.{chip} import components/ui/link.{a} import gleam/list import gleam/string import lustre/attribute.{type Attribute, class, href} -import lustre/element.{type Element, text} +import lustre/element.{type Element, fragment, text} import lustre/element/html.{div, h2, h3, li, ul} import model/route.{type Page, type Pages, is_active} @@ -36,18 +37,27 @@ fn item(route: Pages, page: Page) -> Element(a) { h3([], [ a( [ - class("pl-6 border-l py-1.5"), + class("pl-6 border-l py-1.5 flex items-center gap-2"), active_variant(is_active(route, page.path)), active_border(is_active(route, page.path)), href(page.path), ], - [text(route.page_name(page))], + [text(route.page_name(page)), status(page)], ), ]), ]) } } +fn status(page: Page) -> Element(a) { + case page.state { + route.None -> fragment([]) + route.New -> chip([chip.flat(chip.Info), chip.sm()], [text("New")]) + route.Updated -> + chip([chip.flat(chip.Warning), chip.sm()], [text("Updated")]) + } +} + fn active_variant(active: Bool) -> Attribute(a) { case active { True -> link.link(link.Primary) diff --git a/app/src/model/route.gleam b/app/src/model/route.gleam index f7fc84b..fb5b861 100644 --- a/app/src/model/route.gleam +++ b/app/src/model/route.gleam @@ -71,32 +71,47 @@ pub const spinner = "/docs/components/spinner" pub const skeleton = "/docs/components/skeleton" +pub type Status { + None + New + Updated +} + pub type Page { - Page(path: String, sub_pages: List(Page)) + Page(path: String, sub_pages: List(Page), state: Status) } pub fn pages() -> List(Page) { [ - Page("Guide", [Page(intro, []), Page(installation, []), Page(colors, [])]), + Page( + "Guide", + [ + Page(intro, [], None), + Page(installation, [], None), + Page(colors, [], None), + ], + None, + ), Page( components, [ - Page(button, []), - Page(input, []), - Page(link, []), - Page(chip, []), - Page(divider, []), - Page(tooltip, []), - Page(avatar, []), - Page(badge, []), - Page(breadcrumbs, []), - Page(switch, []), - Page(kbd, []), - Page(checkbox, []), - Page(spinner, []), - Page(skeleton, []), + Page(button, [], None), + Page(input, [], None), + Page(link, [], None), + Page(chip, [], None), + Page(divider, [], Updated), + 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), ] |> sort_pages, + None, ), ] } diff --git a/app/ssg b/app/ssg index a548431..eb59453 100755 --- a/app/ssg +++ b/app/ssg @@ -3,9 +3,12 @@ mkdir -p ./dist/docs/guide/{introduction,installation,colors} mkdir -p ./dist/docs/components/{button,input,link,chip,divider,tooltip,avatar,badge,breadcrumbs,switch,kbd,checkbox,spinner,skeleton} +cp ./dist/index.html ./dist/docs/ +cp ./dist/index.html ./dist/docs/guide/ cp ./dist/index.html ./dist/docs/guide/introduction/ cp ./dist/index.html ./dist/docs/guide/installation/ cp ./dist/index.html ./dist/docs/guide/colors/ +cp ./dist/index.html ./dist/docs/components/ cp ./dist/index.html ./dist/docs/components/button/ cp ./dist/index.html ./dist/docs/components/input/ cp ./dist/index.html ./dist/docs/components/link/ From d5745ebc96db0635f22372bd11843abc830c1da1 Mon Sep 17 00:00:00 2001 From: mahcodes Date: Sun, 12 May 2024 14:41:24 +0300 Subject: [PATCH 12/17] feat: new `slider` component --- app/src/components/aside.gleam | 4 +- app/src/components/ui/slider.gleam | 251 ++++++++++++++++++ app/src/gleez_ui.gleam | 2 + app/src/model/route.gleam | 6 + app/src/pages/demo/demo.gleam | 36 +-- .../docs/components/slider/attributes.gleam | 43 +++ .../pages/docs/components/slider/slider.gleam | 17 ++ .../docs/components/slider/variants.gleam | 158 +++++++++++ app/src/pages/page.gleam | 3 + app/ssg | 3 +- 10 files changed, 490 insertions(+), 33 deletions(-) create mode 100644 app/src/components/ui/slider.gleam create mode 100644 app/src/pages/docs/components/slider/attributes.gleam create mode 100644 app/src/pages/docs/components/slider/slider.gleam create mode 100644 app/src/pages/docs/components/slider/variants.gleam diff --git a/app/src/components/aside.gleam b/app/src/components/aside.gleam index 52c8f3a..cc91686 100644 --- a/app/src/components/aside.gleam +++ b/app/src/components/aside.gleam @@ -4,7 +4,7 @@ import gleam/list import gleam/string import lustre/attribute.{type Attribute, class, href} import lustre/element.{type Element, fragment, text} -import lustre/element/html.{div, h2, h3, li, ul} +import lustre/element/html.{div, h2, h3, li, span, ul} import model/route.{type Page, type Pages, is_active} pub fn aside(route: Pages) -> Element(a) { @@ -42,7 +42,7 @@ fn item(route: Pages, page: Page) -> Element(a) { active_border(is_active(route, page.path)), href(page.path), ], - [text(route.page_name(page)), status(page)], + [span([], [text(route.page_name(page))]), status(page)], ), ]), ]) diff --git a/app/src/components/ui/slider.gleam b/app/src/components/ui/slider.gleam new file mode 100644 index 0000000..e09684b --- /dev/null +++ b/app/src/components/ui/slider.gleam @@ -0,0 +1,251 @@ +import gleam/list +import gleam/string +import lustre/attribute.{type Attribute, class, type_} +import lustre/element.{type Element} +import lustre/element/html.{input} + +pub type Colors { + Neutral + Primary + Secondary + Success + Info + Warning + Danger +} + +pub fn slider(attributes: List(Attribute(a))) -> Element(a) { + input([ + class( + [ + "bg-transparent cursor-pointer disabled:opacity-50 disabled:pointer-events-none focus:outline-none", + "appearance-none [&::-webkit-slider-thumb]:appearance-none [&::-moz-range-thumb]:appearance-none", + "[&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-runnable-track]:rounded-full", + "[&::-webkit-slider-runnable-track]:h-1.5 [&::-moz-range-track]:h-1.5", + "[&::-moz-range-thumb]:rounded-full [&::-moz-range-track]:rounded-full", + "[&::-webkit-slider-runnable-track]:w-full [&::-moz-range-track]:w-full", + "[&::-webkit-slider-thumb]:transition-all [&::-moz-range-thumb]:transition-all", + "[&::-webkit-slider-thumb]:shadow-[0_0_0_4px] [&::-moz-range-thumb]:border-4", + ] + |> string.join(" "), + ), + type_("range"), + ..attributes + ]) +} + +pub fn solid(color: Colors) -> Attribute(a) { + case color { + Neutral -> [ + "[&::-webkit-slider-thumb]:bg-neutral [&::-moz-range-thumb]:bg-neutral", + "[&::-webkit-slider-runnable-track]:bg-neutral [&::-moz-range-track]:bg-neutral", + "[&::-webkit-slider-thumb]:shadow-neutral [&::-moz-range-thumb]:border-neutral", + ] + Primary -> [ + "[&::-webkit-slider-thumb]:bg-primary [&::-moz-range-thumb]:bg-primary", + "[&::-webkit-slider-runnable-track]:bg-primary [&::-moz-range-track]:bg-primary", + "[&::-webkit-slider-thumb]:shadow-primary [&::-moz-range-thumb]:border-primary", + ] + Secondary -> [ + "[&::-webkit-slider-thumb]:bg-secondary [&::-moz-range-thumb]:bg-secondary", + "[&::-webkit-slider-runnable-track]:bg-secondary [&::-moz-range-track]:bg-secondary", + "[&::-webkit-slider-thumb]:shadow-secondary [&::-moz-range-thumb]:border-secondary", + ] + Success -> [ + "[&::-webkit-slider-thumb]:bg-success [&::-moz-range-thumb]:bg-success", + "[&::-webkit-slider-runnable-track]:bg-success [&::-moz-range-track]:bg-success", + "[&::-webkit-slider-thumb]:shadow-success [&::-moz-range-thumb]:border-success", + ] + Info -> [ + "[&::-webkit-slider-thumb]:bg-info [&::-moz-range-thumb]:bg-info", + "[&::-webkit-slider-runnable-track]:bg-info [&::-moz-range-track]:bg-info", + "[&::-webkit-slider-thumb]:shadow-info [&::-moz-range-thumb]:border-info", + ] + Warning -> [ + "[&::-webkit-slider-thumb]:bg-warning [&::-moz-range-thumb]:bg-warning", + "[&::-webkit-slider-runnable-track]:bg-warning [&::-moz-range-track]:bg-warning", + "[&::-webkit-slider-thumb]:shadow-warning [&::-moz-range-thumb]:border-warning", + ] + Danger -> [ + "[&::-webkit-slider-thumb]:bg-danger [&::-moz-range-thumb]:bg-danger", + "[&::-webkit-slider-runnable-track]:bg-danger [&::-moz-range-track]:bg-danger", + "[&::-webkit-slider-thumb]:shadow-danger [&::-moz-range-thumb]:border-danger", + ] + } + |> string.join(" ") + |> class +} + +pub fn outlined(color: Colors) -> Attribute(a) { + case color { + Neutral -> [ + "[&::-webkit-slider-thumb]:bg-neutral-foreground [&::-moz-range-thumb]:bg-neutral-foreground", + "[&::-webkit-slider-runnable-track]:bg-neutral [&::-moz-range-track]:bg-neutral", + "[&::-webkit-slider-thumb]:shadow-neutral [&::-moz-range-thumb]:border-neutral", + ] + Primary -> [ + "[&::-webkit-slider-thumb]:bg-primary-foreground [&::-moz-range-thumb]:bg-primary-foreground", + "[&::-webkit-slider-runnable-track]:bg-primary [&::-moz-range-track]:bg-primary", + "[&::-webkit-slider-thumb]:shadow-primary [&::-moz-range-thumb]:border-primary", + ] + Secondary -> [ + "[&::-webkit-slider-thumb]:bg-secondary-foreground [&::-moz-range-thumb]:bg-secondary-foreground", + "[&::-webkit-slider-runnable-track]:bg-secondary [&::-moz-range-track]:bg-secondary", + "[&::-webkit-slider-thumb]:shadow-secondary [&::-moz-range-thumb]:border-secondary", + ] + Success -> [ + "[&::-webkit-slider-thumb]:bg-success-foreground [&::-moz-range-thumb]:bg-success-foreground", + "[&::-webkit-slider-runnable-track]:bg-success [&::-moz-range-track]:bg-success", + "[&::-webkit-slider-thumb]:shadow-success [&::-moz-range-thumb]:border-success", + ] + Info -> [ + "[&::-webkit-slider-thumb]:bg-info-foreground [&::-moz-range-thumb]:bg-info-foreground", + "[&::-webkit-slider-runnable-track]:bg-info [&::-moz-range-track]:bg-info", + "[&::-webkit-slider-thumb]:shadow-info [&::-moz-range-thumb]:border-info", + ] + Warning -> [ + "[&::-webkit-slider-thumb]:bg-warning-foreground [&::-moz-range-thumb]:bg-warning-foreground", + "[&::-webkit-slider-runnable-track]:bg-warning [&::-moz-range-track]:bg-warning", + "[&::-webkit-slider-thumb]:shadow-warning [&::-moz-range-thumb]:border-warning", + ] + Danger -> [ + "[&::-webkit-slider-thumb]:bg-danger-foreground [&::-moz-range-thumb]:bg-danger-foreground", + "[&::-webkit-slider-runnable-track]:bg-danger [&::-moz-range-track]:bg-danger", + "[&::-webkit-slider-thumb]:shadow-danger [&::-moz-range-thumb]:border-danger", + ] + } + |> string.join(" ") + |> class +} + +pub fn flat(color: Colors) -> Attribute(a) { + case color { + Neutral -> [ + "[&::-webkit-slider-thumb]:bg-neutral [&::-moz-range-thumb]:bg-neutral", + "[&::-webkit-slider-runnable-track]:bg-neutral/20 [&::-moz-range-track]:bg-neutral/20", + "[&:hover::-webkit-slider-runnable-track]:bg-neutral/30 [&:hover::-moz-range-track]:bg-neutral/30", + "[&::-webkit-slider-thumb]:shadow-neutral [&::-moz-range-thumb]:border-neutral", + ] + Primary -> [ + "[&::-webkit-slider-thumb]:bg-primary [&::-moz-range-thumb]:bg-primary", + "[&::-webkit-slider-runnable-track]:bg-primary/20 [&::-moz-range-track]:bg-primary/20", + "[&:hover::-webkit-slider-runnable-track]:bg-primary/30 [&:hover::-moz-range-track]:bg-primary/30", + "[&::-webkit-slider-thumb]:shadow-primary [&::-moz-range-thumb]:border-primary", + ] + Secondary -> [ + "[&::-webkit-slider-thumb]:bg-secondary [&::-moz-range-thumb]:bg-secondary", + "[&::-webkit-slider-runnable-track]:bg-secondary/20 [&::-moz-range-track]:bg-secondary/20", + "[&:hover::-webkit-slider-runnable-track]:bg-secondary/30 [&:hover::-moz-range-track]:bg-secondary/30", + "[&::-webkit-slider-thumb]:shadow-secondary [&::-moz-range-thumb]:border-secondary", + ] + Success -> [ + "[&::-webkit-slider-thumb]:bg-success [&::-moz-range-thumb]:bg-success", + "[&::-webkit-slider-runnable-track]:bg-success/20 [&::-moz-range-track]:bg-success/20", + "[&:hover::-webkit-slider-runnable-track]:bg-success/30 [&:hover::-moz-range-track]:bg-success/30", + "[&::-webkit-slider-thumb]:shadow-success [&::-moz-range-thumb]:border-success", + ] + Info -> [ + "[&::-webkit-slider-thumb]:bg-info [&::-moz-range-thumb]:bg-info", + "[&::-webkit-slider-runnable-track]:bg-info/20 [&::-moz-range-track]:bg-info/20", + "[&:hover::-webkit-slider-runnable-track]:bg-info/30 [&:hover::-moz-range-track]:bg-info/30", + "[&::-webkit-slider-thumb]:shadow-info [&::-moz-range-thumb]:border-info", + ] + Warning -> [ + "[&::-webkit-slider-thumb]:bg-warning [&::-moz-range-thumb]:bg-warning", + "[&::-webkit-slider-runnable-track]:bg-warning/20 [&::-moz-range-track]:bg-warning/20", + "[&:hover::-webkit-slider-runnable-track]:bg-warning/30 [&:hover::-moz-range-track]:bg-warning/30", + "[&::-webkit-slider-thumb]:shadow-warning [&::-moz-range-thumb]:border-warning", + ] + Danger -> [ + "[&::-webkit-slider-thumb]:bg-danger [&::-moz-range-thumb]:bg-danger", + "[&::-webkit-slider-runnable-track]:bg-danger/20 [&::-moz-range-track]:bg-danger/20", + "[&:hover::-webkit-slider-runnable-track]:bg-danger/30 [&:hover::-moz-range-track]:bg-danger/30", + "[&::-webkit-slider-thumb]:shadow-danger [&::-moz-range-thumb]:border-danger", + ] + } + |> string.join(" ") + |> class +} + +pub fn ghost(color: Colors) -> Attribute(a) { + case color { + Neutral -> [ + "[&::-webkit-slider-thumb]:bg-neutral-foreground [&::-moz-range-thumb]:bg-neutral-foreground", + "[&:hover::-webkit-slider-thumb]:bg-neutral [&:hover::-moz-range-thumb]:bg-neutral", + "[&::-webkit-slider-runnable-track]:bg-neutral [&::-moz-range-track]:bg-neutral", + "[&::-webkit-slider-thumb]:shadow-neutral [&::-moz-range-thumb]:border-neutral", + ] + Primary -> [ + "[&::-webkit-slider-thumb]:bg-primary-foreground [&::-moz-range-thumb]:bg-primary-foreground", + "[&:hover::-webkit-slider-thumb]:bg-primary [&:hover::-moz-range-thumb]:bg-primary", + "[&::-webkit-slider-runnable-track]:bg-primary [&::-moz-range-track]:bg-primary", + "[&::-webkit-slider-thumb]:shadow-primary [&::-moz-range-thumb]:border-primary", + ] + Secondary -> [ + "[&::-webkit-slider-thumb]:bg-secondary-foreground [&::-moz-range-thumb]:bg-secondary-foreground", + "[&:hover::-webkit-slider-thumb]:bg-secondary [&:hover::-moz-range-thumb]:bg-secondary", + "[&::-webkit-slider-runnable-track]:bg-secondary [&::-moz-range-track]:bg-secondary", + "[&::-webkit-slider-thumb]:shadow-secondary [&::-moz-range-thumb]:border-secondary", + ] + Success -> [ + "[&::-webkit-slider-thumb]:bg-success-foreground [&::-moz-range-thumb]:bg-success-foreground", + "[&:hover::-webkit-slider-thumb]:bg-success [&:hover::-moz-range-thumb]:bg-success", + "[&::-webkit-slider-runnable-track]:bg-success [&::-moz-range-track]:bg-success", + "[&::-webkit-slider-thumb]:shadow-success [&::-moz-range-thumb]:border-success", + ] + Info -> [ + "[&::-webkit-slider-thumb]:bg-info-foreground [&::-moz-range-thumb]:bg-info-foreground", + "[&:hover::-webkit-slider-thumb]:bg-info [&:hover::-moz-range-thumb]:bg-info", + "[&::-webkit-slider-runnable-track]:bg-info [&::-moz-range-track]:bg-info", + "[&::-webkit-slider-thumb]:shadow-info [&::-moz-range-thumb]:border-info", + ] + Warning -> [ + "[&::-webkit-slider-thumb]:bg-warning-foreground [&::-moz-range-thumb]:bg-warning-foreground", + "[&:hover::-webkit-slider-thumb]:bg-warning [&:hover::-moz-range-thumb]:bg-warning", + "[&::-webkit-slider-runnable-track]:bg-warning [&::-moz-range-track]:bg-warning", + "[&::-webkit-slider-thumb]:shadow-warning [&::-moz-range-thumb]:border-warning", + ] + Danger -> [ + "[&::-webkit-slider-thumb]:bg-danger-foreground [&::-moz-range-thumb]:bg-danger-foreground", + "[&:hover::-webkit-slider-thumb]:bg-danger [&:hover::-moz-range-thumb]:bg-danger", + "[&::-webkit-slider-runnable-track]:bg-danger [&::-moz-range-track]:bg-danger", + "[&::-webkit-slider-thumb]:shadow-danger [&::-moz-range-thumb]:border-danger", + ] + } + |> list.append([ + "[&::-webkit-slider-thumb]:shadow-[0_0_0_4px]", + "[&::-moz-range-thumb]:border-4", + ]) + |> string.join(" ") + |> class +} + +pub fn sm() -> Attribute(a) { + [ + "py-2", "[&::-webkit-slider-thumb]:-mt-[0.0625rem]", + "[&::-webkit-slider-thumb]:w-2 [&::-webkit-slider-thumb]:h-2", + "[&::-moz-range-thumb]:w-2 [&::-moz-range-thumb]:h-2", + ] + |> string.join(" ") + |> class +} + +pub fn md() -> Attribute(a) { + [ + "py-2.5", "[&::-webkit-slider-thumb]:-mt-[0.1875rem]", + "[&::-webkit-slider-thumb]:w-3 [&::-webkit-slider-thumb]:h-3", + "[&::-moz-range-thumb]:w-3 [&::-moz-range-thumb]:h-3", + ] + |> string.join(" ") + |> class +} + +pub fn lg() -> Attribute(a) { + [ + "py-3", "[&::-webkit-slider-thumb]:-mt-[0.313rem]", + "[&::-webkit-slider-thumb]:w-4 [&::-webkit-slider-thumb]:h-4", + "[&::-moz-range-thumb]:w-4 [&::-moz-range-thumb]:h-4", + ] + |> string.join(" ") + |> class +} diff --git a/app/src/gleez_ui.gleam b/app/src/gleez_ui.gleam index 37cc92b..5c13ab0 100644 --- a/app/src/gleez_ui.gleam +++ b/app/src/gleez_ui.gleam @@ -49,6 +49,7 @@ fn on_url_change(uri: Uri) -> Msg { ["docs", "components", "checkbox"] -> OnRouteChange(route.Checkbox) ["docs", "components", "spinner"] -> OnRouteChange(route.Spinner) ["docs", "components", "skeleton"] -> OnRouteChange(route.Skeleton) + ["docs", "components", "slider"] -> OnRouteChange(route.Slider) _ -> OnRouteChange(route.Home) } } @@ -142,6 +143,7 @@ fn with_aside(model: Model) -> Element(Msg) { route.Checkbox -> page.checkbox() route.Spinner -> page.spinner() route.Skeleton -> page.skeleton() + route.Slider -> page.slider() _ -> page.home() }, ]), diff --git a/app/src/model/route.gleam b/app/src/model/route.gleam index fb5b861..9626402 100644 --- a/app/src/model/route.gleam +++ b/app/src/model/route.gleam @@ -25,6 +25,7 @@ pub type Pages { Checkbox Spinner Skeleton + Slider } pub const home = "/" @@ -71,6 +72,8 @@ pub const spinner = "/docs/components/spinner" pub const skeleton = "/docs/components/skeleton" +pub const slider = "/docs/components/slider" + pub type Status { None New @@ -109,6 +112,7 @@ pub fn pages() -> List(Page) { Page(checkbox, [], New), Page(spinner, [], New), Page(skeleton, [], New), + Page(slider, [], New), ] |> sort_pages, None, @@ -139,6 +143,7 @@ pub fn to_path(page: Pages) -> String { Checkbox -> checkbox Spinner -> spinner Skeleton -> skeleton + Slider -> slider } } @@ -164,6 +169,7 @@ pub fn to_pages(path: String) -> Pages { p if p == checkbox -> Checkbox p if p == spinner -> Spinner p if p == skeleton -> Skeleton + p if p == slider -> Slider _ -> Home } } diff --git a/app/src/pages/demo/demo.gleam b/app/src/pages/demo/demo.gleam index afac30d..15ddb4e 100644 --- a/app/src/pages/demo/demo.gleam +++ b/app/src/pages/demo/demo.gleam @@ -1,36 +1,12 @@ -import components/ui/skeleton.{skeleton} +import components/ui/slider.{slider} import lustre/attribute.{class} import lustre/element.{type Element} import lustre/element/html.{div} pub fn demo() -> Element(a) { - div( - [ - class( - "flex flex-col items-center gap-4 bg-neutral-foreground p-4 rounded-md max-w-xs", - ), - ], - [ - skeleton([ - class("w-full aspect-video rounded-md"), - skeleton.solid(skeleton.Neutral), - ]), - div([class("flex items-center w-full gap-4")], [ - skeleton([ - class("w-12 h-12 rounded-full"), - skeleton.solid(skeleton.Neutral), - ]), - div([class("flex flex-col flex-1 gap-2")], [ - skeleton([ - class("w-full h-4 rounded"), - skeleton.solid(skeleton.Neutral), - ]), - skeleton([ - class("w-2/3 h-4 rounded"), - skeleton.solid(skeleton.Neutral), - ]), - ]), - ]), - ], - ) + 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()]), + ]) } diff --git a/app/src/pages/docs/components/slider/attributes.gleam b/app/src/pages/docs/components/slider/attributes.gleam new file mode 100644 index 0000000..34da9de --- /dev/null +++ b/app/src/pages/docs/components/slider/attributes.gleam @@ -0,0 +1,43 @@ +import components/ui/slider.{slider} +import lustre/attribute.{class} +import lustre/element.{type Element} +import lustre/element/html.{div} +import pages/docs/sections/section + +pub fn attributes() -> Element(a) { + section.attributes([ + section.attribute( + "Size", + " +- `sm()`: Small Size +- `md()`: Medium Size +- `lg()`: Large Size + ", + [ + div([class("flex flex-col gap-2 py-2 w-full max-w-xs")], [ + slider([slider.outlined(slider.Neutral), slider.sm()]), + slider([slider.outlined(slider.Neutral), slider.md()]), + slider([slider.outlined(slider.Neutral), slider.lg()]), + ]), + ], + size_code(), + ), + ]) +} + +fn size_code() -> String { + " +import components/ui/slider.{slider} +import lustre/attribute.{class} +import lustre/element.{type Element} +import lustre/element/html.{div} + +pub fn demo() -> Element(a) { + div([class(\"flex flex-col gap-2 py-2 w-full max-w-xs\")], [ + slider([slider.outlined(slider.Neutral), slider.sm()]), + slider([slider.outlined(slider.Neutral), slider.md()]), + slider([slider.outlined(slider.Neutral), slider.lg()]), + ]) +} +" +} diff --git a/app/src/pages/docs/components/slider/slider.gleam b/app/src/pages/docs/components/slider/slider.gleam new file mode 100644 index 0000000..cca7863 --- /dev/null +++ b/app/src/pages/docs/components/slider/slider.gleam @@ -0,0 +1,17 @@ +import components/prose.{prose} +import lustre/element.{type Element} +import pages/docs/components/slider/attributes.{attributes} +import pages/docs/components/slider/variants.{variants} +import pages/docs/sections/section + +pub fn docs() -> Element(a) { + prose([], [ + section.intro( + "Slider", + "The slider can be used to set the start and end of a range by supplying an array of values to the value prop.", + ), + section.installation("gleam run -m gleez add slider"), + variants(), + attributes(), + ]) +} diff --git a/app/src/pages/docs/components/slider/variants.gleam b/app/src/pages/docs/components/slider/variants.gleam new file mode 100644 index 0000000..3588ee1 --- /dev/null +++ b/app/src/pages/docs/components/slider/variants.gleam @@ -0,0 +1,158 @@ +import components/ui/slider.{slider} +import lustre/attribute.{class} +import lustre/element.{type Element} +import lustre/element/html.{div} +import pages/docs/sections/section + +pub fn variants() -> Element(a) { + section.variants([ + section.variant( + "Solid", + "", + [ + div([class("flex flex-col gap-2 py-2 w-full max-w-xs")], [ + slider([slider.solid(slider.Neutral), slider.md()]), + slider([slider.solid(slider.Primary), slider.md()]), + slider([slider.solid(slider.Secondary), slider.md()]), + slider([slider.solid(slider.Success), slider.md()]), + slider([slider.solid(slider.Info), slider.md()]), + slider([slider.solid(slider.Warning), slider.md()]), + slider([slider.solid(slider.Danger), slider.md()]), + ]), + ], + solid_code(), + ), + section.variant( + "Outlined", + "", + [ + div([class("flex flex-col gap-2 py-2 w-full max-w-xs")], [ + slider([slider.outlined(slider.Neutral), slider.md()]), + slider([slider.outlined(slider.Primary), slider.md()]), + slider([slider.outlined(slider.Secondary), slider.md()]), + slider([slider.outlined(slider.Success), slider.md()]), + slider([slider.outlined(slider.Info), slider.md()]), + slider([slider.outlined(slider.Warning), slider.md()]), + slider([slider.outlined(slider.Danger), slider.md()]), + ]), + ], + outlined_code(), + ), + section.variant( + "Flat", + "", + [ + div([class("flex flex-col gap-2 py-2 w-full max-w-xs")], [ + slider([slider.flat(slider.Neutral), slider.md()]), + slider([slider.flat(slider.Primary), slider.md()]), + slider([slider.flat(slider.Secondary), slider.md()]), + slider([slider.flat(slider.Success), slider.md()]), + slider([slider.flat(slider.Info), slider.md()]), + slider([slider.flat(slider.Warning), slider.md()]), + slider([slider.flat(slider.Danger), slider.md()]), + ]), + ], + flat_code(), + ), + section.variant( + "Ghost", + "", + [ + div([class("flex flex-col gap-2 py-2 w-full max-w-xs")], [ + slider([slider.ghost(slider.Neutral), slider.md()]), + slider([slider.ghost(slider.Primary), slider.md()]), + slider([slider.ghost(slider.Secondary), slider.md()]), + slider([slider.ghost(slider.Success), slider.md()]), + slider([slider.ghost(slider.Info), slider.md()]), + slider([slider.ghost(slider.Warning), slider.md()]), + slider([slider.ghost(slider.Danger), slider.md()]), + ]), + ], + ghost_code(), + ), + ]) +} + +fn solid_code() -> String { + " +import components/ui/slider.{slider} +import lustre/attribute.{class} +import lustre/element.{type Element} +import lustre/element/html.{div} + +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.md()]), + slider([slider.solid(slider.Primary), slider.md()]), + slider([slider.solid(slider.Secondary), slider.md()]), + slider([slider.solid(slider.Success), slider.md()]), + slider([slider.solid(slider.Info), slider.md()]), + slider([slider.solid(slider.Warning), slider.md()]), + slider([slider.solid(slider.Danger), slider.md()]), + ]) +} +" +} + +fn outlined_code() -> String { + " +import components/ui/slider.{slider} +import lustre/attribute.{class} +import lustre/element.{type Element} +import lustre/element/html.{div} + +pub fn demo() -> Element(a) { + div([class(\"flex flex-col gap-2 py-2 w-full max-w-xs\")], [ + slider([slider.outlined(slider.Neutral), slider.md()]), + slider([slider.outlined(slider.Primary), slider.md()]), + slider([slider.outlined(slider.Secondary), slider.md()]), + slider([slider.outlined(slider.Success), slider.md()]), + slider([slider.outlined(slider.Info), slider.md()]), + slider([slider.outlined(slider.Warning), slider.md()]), + slider([slider.outlined(slider.Danger), slider.md()]), + ]) +} +" +} + +fn flat_code() -> String { + " +import components/ui/slider.{slider} +import lustre/attribute.{class} +import lustre/element.{type Element} +import lustre/element/html.{div} + +pub fn demo() -> Element(a) { + div([class(\"flex flex-col gap-2 py-2 w-full max-w-xs\")], [ + slider([slider.flat(slider.Neutral), slider.md()]), + slider([slider.flat(slider.Primary), slider.md()]), + slider([slider.flat(slider.Secondary), slider.md()]), + slider([slider.flat(slider.Success), slider.md()]), + slider([slider.flat(slider.Info), slider.md()]), + slider([slider.flat(slider.Warning), slider.md()]), + slider([slider.flat(slider.Danger), slider.md()]), + ]) +} +" +} + +fn ghost_code() -> String { + " +import components/ui/slider.{slider} +import lustre/attribute.{class} +import lustre/element.{type Element} +import lustre/element/html.{div} + +pub fn demo() -> Element(a) { + div([class(\"flex flex-col gap-2 py-2 w-full max-w-xs\")], [ + slider([slider.ghost(slider.Neutral), slider.md()]), + slider([slider.ghost(slider.Primary), slider.md()]), + slider([slider.ghost(slider.Secondary), slider.md()]), + slider([slider.ghost(slider.Success), slider.md()]), + slider([slider.ghost(slider.Info), slider.md()]), + slider([slider.ghost(slider.Warning), slider.md()]), + slider([slider.ghost(slider.Danger), slider.md()]), + ]) +} +" +} diff --git a/app/src/pages/page.gleam b/app/src/pages/page.gleam index 4b914b5..e3e0740 100644 --- a/app/src/pages/page.gleam +++ b/app/src/pages/page.gleam @@ -8,6 +8,7 @@ import pages/docs/components/checkbox/checkbox import pages/docs/components/chip/chip import pages/docs/components/divider/divider import pages/docs/components/input/input +import pages/docs/components/slider/slider import pages/docs/components/kbd/kbd import pages/docs/components/link/link import pages/docs/components/spinner/spinner @@ -60,3 +61,5 @@ pub const checkbox = checkbox.docs pub const spinner = spinner.docs pub const skeleton = skeleton.docs + +pub const slider = slider.docs diff --git a/app/ssg b/app/ssg index eb59453..3a3a762 100755 --- a/app/ssg +++ b/app/ssg @@ -1,7 +1,7 @@ #!/bin/bash mkdir -p ./dist/docs/guide/{introduction,installation,colors} -mkdir -p ./dist/docs/components/{button,input,link,chip,divider,tooltip,avatar,badge,breadcrumbs,switch,kbd,checkbox,spinner,skeleton} +mkdir -p ./dist/docs/components/{button,input,link,chip,divider,tooltip,avatar,badge,breadcrumbs,switch,kbd,checkbox,spinner,skeleton,slider} cp ./dist/index.html ./dist/docs/ cp ./dist/index.html ./dist/docs/guide/ @@ -23,3 +23,4 @@ cp ./dist/index.html ./dist/docs/components/kbd/ cp ./dist/index.html ./dist/docs/components/checkbox/ cp ./dist/index.html ./dist/docs/components/spinner/ cp ./dist/index.html ./dist/docs/components/skeleton/ +cp ./dist/index.html ./dist/docs/components/slider/ From 79e1978df5dc4bbdf7e91186cc393920dda2b8c2 Mon Sep 17 00:00:00 2001 From: mahcodes Date: Sun, 12 May 2024 14:45:00 +0300 Subject: [PATCH 13/17] fix(docs): rm slider preview `py-2`, + gap --- .../docs/components/slider/attributes.gleam | 4 ++-- .../pages/docs/components/slider/variants.gleam | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/src/pages/docs/components/slider/attributes.gleam b/app/src/pages/docs/components/slider/attributes.gleam index 34da9de..09d0f7d 100644 --- a/app/src/pages/docs/components/slider/attributes.gleam +++ b/app/src/pages/docs/components/slider/attributes.gleam @@ -14,7 +14,7 @@ pub fn attributes() -> Element(a) { - `lg()`: Large Size ", [ - div([class("flex flex-col gap-2 py-2 w-full max-w-xs")], [ + div([class("flex flex-col gap-4 w-full max-w-xs")], [ slider([slider.outlined(slider.Neutral), slider.sm()]), slider([slider.outlined(slider.Neutral), slider.md()]), slider([slider.outlined(slider.Neutral), slider.lg()]), @@ -33,7 +33,7 @@ import lustre/element.{type Element} import lustre/element/html.{div} pub fn demo() -> Element(a) { - div([class(\"flex flex-col gap-2 py-2 w-full max-w-xs\")], [ + div([class(\"flex flex-col gap-4 w-full max-w-xs\")], [ slider([slider.outlined(slider.Neutral), slider.sm()]), slider([slider.outlined(slider.Neutral), slider.md()]), slider([slider.outlined(slider.Neutral), slider.lg()]), diff --git a/app/src/pages/docs/components/slider/variants.gleam b/app/src/pages/docs/components/slider/variants.gleam index 3588ee1..120860e 100644 --- a/app/src/pages/docs/components/slider/variants.gleam +++ b/app/src/pages/docs/components/slider/variants.gleam @@ -10,7 +10,7 @@ pub fn variants() -> Element(a) { "Solid", "", [ - div([class("flex flex-col gap-2 py-2 w-full max-w-xs")], [ + div([class("flex flex-col gap-4 w-full max-w-xs")], [ slider([slider.solid(slider.Neutral), slider.md()]), slider([slider.solid(slider.Primary), slider.md()]), slider([slider.solid(slider.Secondary), slider.md()]), @@ -26,7 +26,7 @@ pub fn variants() -> Element(a) { "Outlined", "", [ - div([class("flex flex-col gap-2 py-2 w-full max-w-xs")], [ + div([class("flex flex-col gap-4 w-full max-w-xs")], [ slider([slider.outlined(slider.Neutral), slider.md()]), slider([slider.outlined(slider.Primary), slider.md()]), slider([slider.outlined(slider.Secondary), slider.md()]), @@ -42,7 +42,7 @@ pub fn variants() -> Element(a) { "Flat", "", [ - div([class("flex flex-col gap-2 py-2 w-full max-w-xs")], [ + div([class("flex flex-col gap-4 w-full max-w-xs")], [ slider([slider.flat(slider.Neutral), slider.md()]), slider([slider.flat(slider.Primary), slider.md()]), slider([slider.flat(slider.Secondary), slider.md()]), @@ -58,7 +58,7 @@ pub fn variants() -> Element(a) { "Ghost", "", [ - div([class("flex flex-col gap-2 py-2 w-full max-w-xs")], [ + div([class("flex flex-col gap-4 w-full max-w-xs")], [ slider([slider.ghost(slider.Neutral), slider.md()]), slider([slider.ghost(slider.Primary), slider.md()]), slider([slider.ghost(slider.Secondary), slider.md()]), @@ -81,7 +81,7 @@ import lustre/element.{type Element} import lustre/element/html.{div} pub fn demo() -> Element(a) { - div([class(\"flex flex-col gap-2 py-2 w-full max-w-xs\")], [ + div([class(\"flex flex-col gap-4 w-full max-w-xs\")], [ slider([slider.solid(slider.Neutral), slider.md()]), slider([slider.solid(slider.Primary), slider.md()]), slider([slider.solid(slider.Secondary), slider.md()]), @@ -102,7 +102,7 @@ import lustre/element.{type Element} import lustre/element/html.{div} pub fn demo() -> Element(a) { - div([class(\"flex flex-col gap-2 py-2 w-full max-w-xs\")], [ + div([class(\"flex flex-col gap-4 w-full max-w-xs\")], [ slider([slider.outlined(slider.Neutral), slider.md()]), slider([slider.outlined(slider.Primary), slider.md()]), slider([slider.outlined(slider.Secondary), slider.md()]), @@ -123,7 +123,7 @@ import lustre/element.{type Element} import lustre/element/html.{div} pub fn demo() -> Element(a) { - div([class(\"flex flex-col gap-2 py-2 w-full max-w-xs\")], [ + div([class(\"flex flex-col gap-4 w-full max-w-xs\")], [ slider([slider.flat(slider.Neutral), slider.md()]), slider([slider.flat(slider.Primary), slider.md()]), slider([slider.flat(slider.Secondary), slider.md()]), @@ -144,7 +144,7 @@ import lustre/element.{type Element} import lustre/element/html.{div} pub fn demo() -> Element(a) { - div([class(\"flex flex-col gap-2 py-2 w-full max-w-xs\")], [ + div([class(\"flex flex-col gap-4 w-full max-w-xs\")], [ slider([slider.ghost(slider.Neutral), slider.md()]), slider([slider.ghost(slider.Primary), slider.md()]), slider([slider.ghost(slider.Secondary), slider.md()]), From 94bb5dd4247c8cbb4518fd3db7c0f5dc432ccba9 Mon Sep 17 00:00:00 2001 From: mahcodes Date: Sun, 12 May 2024 15:19:52 +0300 Subject: [PATCH 14/17] feat(nav): added releases link --- app/src/components/nav.gleam | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/app/src/components/nav.gleam b/app/src/components/nav.gleam index a139a59..7300d9b 100644 --- a/app/src/components/nav.gleam +++ b/app/src/components/nav.gleam @@ -1,7 +1,9 @@ import components/ui/link.{a} -import lustre/attribute.{type Attribute, class, href} -import lustre/element.{type Element, text} +import gleam/string +import lustre/attribute.{type Attribute, class, href, target} +import lustre/element.{type Element, fragment, text} import lustre/element/html.{li, ul} +import lustre/ui/icon import model/route.{type Pages, is_active} fn active_variant(active: Bool) -> Attribute(a) { @@ -14,14 +16,34 @@ fn active_variant(active: Bool) -> Attribute(a) { pub fn nav(route: Pages) -> Element(a) { html.nav([], [ ul([class("flex gap-8 pl-8 text-sm")], [ - item(route, route.components), item(route, route.docs), + item(route, route.components), + item(route, "https://github.com/MAHcodes/gleez/releases"), // item(route, route.blog), // item(route, route.demo), ]), ]) } +fn is_internal(path: String) -> Bool { + path + |> string.starts_with("/") +} + +fn tgt(path: String) -> Attribute(a) { + case is_internal(path) { + True -> target("_self") + False -> target("_blank") + } +} + +fn icon(path: String) -> Element(a) { + case is_internal(path) { + True -> fragment([]) + False -> icon.external_link([class("w-4")]) + } +} + fn item(route: Pages, path: String) -> Element(a) { li([], [ a( @@ -29,8 +51,9 @@ fn item(route: Pages, path: String) -> Element(a) { href(path), link.underline(link.Hover), active_variant(is_active(route, path)), + tgt(path), ], - [text(route.path_name(path))], + [html.span([], [text(route.path_name(path))]), icon(path)], ), ]) } From cb074bcd28283317cc22c2908f55a738005de92f Mon Sep 17 00:00:00 2001 From: mahcodes Date: Sun, 12 May 2024 15:28:07 +0300 Subject: [PATCH 15/17] fix(config): add tailwindcss purge safelist --- app/tailwind.config.cjs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/tailwind.config.cjs b/app/tailwind.config.cjs index cf92677..3e192e3 100644 --- a/app/tailwind.config.cjs +++ b/app/tailwind.config.cjs @@ -5,6 +5,15 @@ module.exports = { future: { hoverOnlyWhenSupported: true, }, + purge: { + safelist: [ + "animate-fade-in", + "animate-fade-out", + "hidden", + "opacity-0", + "invisible", + ], + }, theme: { container: { center: true, From 24611a431b6c813109da023063efe4feeb060843 Mon Sep 17 00:00:00 2001 From: mahcodes Date: Sun, 12 May 2024 16:03:30 +0300 Subject: [PATCH 16/17] fix(docs): redirect to home page on load --- app/src/assets/js/ffi.mjs | 20 ++++++++++++++-- app/src/gleez_ui.gleam | 6 ++--- app/src/model/route.gleam | 48 +++++++++++++++++++-------------------- 3 files changed, 45 insertions(+), 29 deletions(-) diff --git a/app/src/assets/js/ffi.mjs b/app/src/assets/js/ffi.mjs index 4958db1..6a4991b 100644 --- a/app/src/assets/js/ffi.mjs +++ b/app/src/assets/js/ffi.mjs @@ -1,3 +1,6 @@ +import { Some, None } from "/build/dev/javascript/gleam_stdlib/gleam/option.mjs"; +import { Uri } from "/build/dev/javascript/gleam_stdlib/gleam/uri.mjs"; + function attach_copy() { const codes = document.querySelectorAll("pre.hljs"); @@ -150,6 +153,19 @@ export function attach_all() { window.requestAnimationFrame(do_attach_all); } -export function pathname() { - return window.location.pathname; +const uri_from_url = (url) => { + return new Uri( + /* scheme */ new (url.protocol ? Some : None)(url.protocol), + /* userinfo */ new None(), + /* host */ new (url.host ? Some : None)(url.host), + /* port */ new (url.port ? Some : None)(url.port), + /* path */ url.pathname, + /* query */ new (url.search ? Some : None)(url.search), + /* fragment */ new (url.hash ? Some : None)(url.hash.slice(1)), + ); +}; + +export function uri() { + const url = new URL(window.location.href); + return uri_from_url(url); } diff --git a/app/src/gleez_ui.gleam b/app/src/gleez_ui.gleam index 5c13ab0..509c22f 100644 --- a/app/src/gleez_ui.gleam +++ b/app/src/gleez_ui.gleam @@ -22,7 +22,7 @@ pub fn main() { fn init(_) -> #(Model, Effect(Msg)) { #( - Model(page: to_pages(pathname()), repo: None), + Model(page: to_pages(uri()), repo: None), batch([fetch_stargazers_count(), modem.init(on_url_change), on_load()]), ) } @@ -65,8 +65,8 @@ fn do_highlight_all() -> Nil @external(javascript, "./assets/js/ffi.mjs", "attach_all") fn do_attach_all() -> Nil -@external(javascript, "./assets/js/ffi.mjs", "pathname") -fn pathname() -> String +@external(javascript, "./assets/js/ffi.mjs", "uri") +fn uri() -> uri.Uri fn attach_all() -> Effect(a) { effect.from(fn(_) { do_attach_all() }) diff --git a/app/src/model/route.gleam b/app/src/model/route.gleam index 9626402..64a8e2c 100644 --- a/app/src/model/route.gleam +++ b/app/src/model/route.gleam @@ -1,7 +1,7 @@ import gleam/list import gleam/result import gleam/string -import gleam/uri +import gleam/uri.{type Uri} pub type Pages { Home @@ -30,49 +30,49 @@ pub type Pages { pub const home = "/" -pub const demo = "/demo" +pub const demo = "/demo/" -pub const blog = "/blog" +pub const blog = "/blog/" -pub const intro = "/docs/guide/introduction" +pub const intro = "/docs/guide/introduction/" -pub const installation = "/docs/guide/installation" +pub const installation = "/docs/guide/installation/" -pub const colors = "/docs/guide/colors" +pub const colors = "/docs/guide/colors/" -pub const docs = "/docs" +pub const docs = "/docs/" pub const components = "/docs/components/" -pub const button = "/docs/components/button" +pub const button = "/docs/components/button/" -pub const input = "/docs/components/input" +pub const input = "/docs/components/input/" -pub const link = "/docs/components/link" +pub const link = "/docs/components/link/" -pub const chip = "/docs/components/chip" +pub const chip = "/docs/components/chip/" -pub const divider = "/docs/components/divider" +pub const divider = "/docs/components/divider/" -pub const tooltip = "/docs/components/tooltip" +pub const tooltip = "/docs/components/tooltip/" -pub const avatar = "/docs/components/avatar" +pub const avatar = "/docs/components/avatar/" -pub const badge = "/docs/components/badge" +pub const badge = "/docs/components/badge/" -pub const breadcrumbs = "/docs/components/breadcrumbs" +pub const breadcrumbs = "/docs/components/breadcrumbs/" -pub const switch = "/docs/components/switch" +pub const switch = "/docs/components/switch/" -pub const kbd = "/docs/components/kbd" +pub const kbd = "/docs/components/kbd/" -pub const checkbox = "/docs/components/checkbox" +pub const checkbox = "/docs/components/checkbox/" -pub const spinner = "/docs/components/spinner" +pub const spinner = "/docs/components/spinner/" -pub const skeleton = "/docs/components/skeleton" +pub const skeleton = "/docs/components/skeleton/" -pub const slider = "/docs/components/slider" +pub const slider = "/docs/components/slider/" pub type Status { None @@ -147,8 +147,8 @@ pub fn to_path(page: Pages) -> String { } } -pub fn to_pages(path: String) -> Pages { - case path { +pub fn to_pages(uri: Uri) -> Pages { + case uri.path { p if p == demo -> Demo p if p == colors -> Colors p if p == intro -> Intro From c5c39d45ae04230e7199c3795d4d7c041a8179b7 Mon Sep 17 00:00:00 2001 From: mahcodes Date: Sun, 12 May 2024 16:23:15 +0300 Subject: [PATCH 17/17] bump v0.2.0 --- gleam.toml | 2 +- src/gleez.gleam | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gleam.toml b/gleam.toml index a459f6f..efe3f75 100644 --- a/gleam.toml +++ b/gleam.toml @@ -1,5 +1,5 @@ name = "gleez" -version = "0.1.2" +version = "0.2.0" description = "gleez cli, an experimental source installer" licences = ["MIT"] diff --git a/src/gleez.gleam b/src/gleez.gleam index c89f4fd..bda2a22 100644 --- a/src/gleez.gleam +++ b/src/gleez.gleam @@ -8,7 +8,7 @@ import gleam/string import simplifile // github tag for the ui components -const tag = "v0.1.0" +const tag = "v0.2.0" // distination path for the installed components const dist = "./src/components/ui/"