Current section

Files

Jump to
glaze_basecoat src glaze basecoat sidebar.gleam
Raw

src/glaze/basecoat/sidebar.gleam

//// Basecoat documentation: <https://basecoatui.com/components/sidebar/>
////
//// Sidebar layout helpers for responsive app navigation.
////
//// **Note**: This component requires JavaScript from Basecoat.
////
//// ## Anatomy
////
//// A sidebar is typically an `aside` with a `nav` containing groups and links.
////
//// ## Recipe
////
//// ```gleam
//// import glaze/basecoat/sidebar
//// import lustre/element/html
////
//// fn main_sidebar() {
//// sidebar.sidebar("main-nav", [sidebar.left()], [
//// sidebar.nav([], [
//// sidebar.section([], [
//// sidebar.group("Getting started", [
//// sidebar.link("#", True, [], [html.text("Playground")]),
//// sidebar.link("#", False, [], [html.text("Models")]),
//// ]),
//// ]),
//// ]),
//// ])
//// }
//// ```
////
//// ## References
////
//// - MDN `aria-current`: <https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Attributes/aria-current>
import glaze/basecoat/internal/listx
import lustre/attribute.{type Attribute}
import lustre/element.{type Element}
import lustre/element/html
pub type Side {
Left
Right
}
pub fn sidebar(
id: String,
attrs: List(Attribute(msg)),
children: List(Element(msg)),
) -> Element(msg) {
html.aside(
[
attribute.class("sidebar"),
attribute.id(id),
attribute.aria_hidden(False),
..attrs
],
children,
)
}
pub fn left() -> Attribute(msg) {
attribute.data("side", "left")
}
pub fn right() -> Attribute(msg) {
attribute.data("side", "right")
}
pub fn hidden() -> Attribute(msg) {
attribute.aria_hidden(True)
}
pub fn visible() -> Attribute(msg) {
attribute.aria_hidden(False)
}
pub fn nav(
attrs: List(Attribute(msg)),
children: List(Element(msg)),
) -> Element(msg) {
html.nav(attrs, children)
}
pub fn nav_with_label(
label: String,
attrs: List(Attribute(msg)),
children: List(Element(msg)),
) -> Element(msg) {
html.nav([attribute.aria_label(label), ..attrs], children)
}
pub fn header(
attrs: List(Attribute(msg)),
children: List(Element(msg)),
) -> Element(msg) {
html.header(attrs, children)
}
pub fn section(
attrs: List(Attribute(msg)),
children: List(Element(msg)),
) -> Element(msg) {
html.section([attribute.class("scrollbar"), ..attrs], children)
}
pub fn group(label: String, items: List(Element(msg))) -> Element(msg) {
let label_id = "group-label-" <> label
html.div(
[
attribute.role("group"),
attribute.aria_labelledby(label_id),
],
[
html.h3([attribute.id(label_id), attribute.class("text-sm font-medium")], [
html.text(label),
]),
html.ul([], items),
],
)
}
pub fn group_with_attrs(
label: String,
attrs: List(Attribute(msg)),
items: List(Element(msg)),
) -> Element(msg) {
let label_id = "group-label-" <> label
html.div(
[attribute.role("group"), attribute.aria_labelledby(label_id), ..attrs],
[
html.h3([attribute.id(label_id), attribute.class("text-sm font-medium")], [
html.text(label),
]),
html.ul([], items),
],
)
}
pub fn link(
href: String,
is_current: Bool,
attrs: List(Attribute(msg)),
children: List(Element(msg)),
) -> Element(msg) {
let current_attr = case is_current {
True -> [attribute.aria_current("page")]
False -> []
}
html.li([], [
html.a(listx.append3([attribute.href(href)], current_attr, attrs), children),
])
}
pub fn button(
is_current: Bool,
attrs: List(Attribute(msg)),
children: List(Element(msg)),
) -> Element(msg) {
let current_attr = case is_current {
True -> [attribute.aria_current("page")]
False -> []
}
html.li([], [
html.button(
listx.append3(
[attribute.type_("button"), attribute.class("w-full text-left")],
current_attr,
attrs,
),
children,
),
])
}
pub fn submenu(
id: String,
label: String,
attrs: List(Attribute(msg)),
items: List(Element(msg)),
) -> Element(msg) {
html.li([], [
html.details([attribute.id(id), ..attrs], [
html.summary([attribute.aria_controls(id <> "-content")], [
html.text(label),
]),
html.ul([attribute.id(id <> "-content")], items),
]),
])
}
pub fn submenu_with_icon(
id: String,
icon: Element(msg),
label: String,
attrs: List(Attribute(msg)),
items: List(Element(msg)),
) -> Element(msg) {
html.li([], [
html.details([attribute.id(id), ..attrs], [
html.summary([attribute.aria_controls(id <> "-content")], [
icon,
html.text(label),
]),
html.ul([attribute.id(id <> "-content")], items),
]),
])
}
pub fn footer(
attrs: List(Attribute(msg)),
children: List(Element(msg)),
) -> Element(msg) {
html.footer(attrs, children)
}
pub fn toggle_script(sidebar_id: String) -> String {
"document.dispatchEvent(new CustomEvent('basecoat:sidebar', { detail: { id: '"
<> sidebar_id
<> "' } }));"
}
pub fn toggle_script_default() -> String {
"document.dispatchEvent(new CustomEvent('basecoat:sidebar'));"
}
pub fn open_script(sidebar_id: String) -> String {
"document.dispatchEvent(new CustomEvent('basecoat:sidebar', { detail: { id: '"
<> sidebar_id
<> "', action: 'open' } }));"
}
pub fn close_script(sidebar_id: String) -> String {
"document.dispatchEvent(new CustomEvent('basecoat:sidebar', { detail: { id: '"
<> sidebar_id
<> "', action: 'close' } }));"
}