Howdy

Alert

Alerts: a message that stands out from the content around it.

componentimport howdy/ui/alertSince Howdy 2.0
gleam run -m howdy/ui add alert

Alerts

Heads up
Copy components with the command line.
Payment failed
Your card was declined.
ui.stack([], [
  ui.alert(alert.Info, [], [
    ui.alert_title([text("Heads up")]),
    ui.alert_description([text("Copy components with the command line.")]),
  ]),
  ui.alert(alert.Danger, [], [
    ui.alert_title([text("Payment failed")]),
    ui.alert_description([text("Your card was declined.")]),
  ]),
])
Full source of howdy/ui/alert
//// Alerts: a message that stands out from the content around it.
////
//// ```gleam
//// alert.alert(alert.Danger, [], [
////   alert.title([text("Payment failed")]),
////   alert.description([text("Your card was declined.")]),
//// ])
//// ```
////
//// An `svg` icon placed first sits to the left of the title and
//// description.
////
//// When an alert appears in response to something the user did, such as
//// a live view reporting an error, pass `attribute.role("alert")` so a
//// screen reader announces it. A message that is part of the page from the
//// start needs no role.

import howdy/ui/style.{class}
import howdy/ui/theme/tokens
import lustre/attribute.{type Attribute}
import lustre/element.{type Element}
import lustre/element/html
import sketch/css.{type Class}
import sketch/css/length.{rem}

pub type Variant {
  /// Information, in the text colour.
  Info
  /// A problem, in the danger colour.
  Danger
}

pub fn alert(
  variant: Variant,
  attributes: List(Attribute(msg)),
  children: List(Element(msg)),
) -> Element(msg) {
  html.div([class(alert_class(variant)), ..attributes], children)
}

pub fn title(children: List(Element(msg))) -> Element(msg) {
  html.div([class(title_class())], children)
}

pub fn description(children: List(Element(msg))) -> Element(msg) {
  html.div([class(description_class())], children)
}

/// Every class this module uses, for `howdy/ui/export`.
pub fn classes() -> List(Class) {
  [alert_class(Info), alert_class(Danger), title_class(), description_class()]
}

pub fn alert_class(variant: Variant) -> Class {
  let colour = case variant {
    Info -> tokens.text
    Danger -> tokens.danger
  }
  css.class([
    css.display("grid"),
    css.grid_template_columns("1fr"),
    css.row_gap(rem(0.125)),
    css.align_items("start"),
    css.padding_(tokens.space_3 <> " " <> tokens.space_4),
    css.background(tokens.surface),
    css.color(colour),
    style.bordered(),
    style.radius(tokens.radius_large),
    css.font_size(rem(0.875)),
    css.selector(":has(> svg)", [
      css.grid_template_columns("1rem 1fr"),
      css.column_gap(rem(0.75)),
    ]),
    css.selector(" > svg", [
      css.grid_row("span 2"),
      css.property("width", "1rem"),
      css.property("height", "1rem"),
      css.property("translate", "0 0.125rem"),
      css.color("currentColor"),
    ]),
  ])
}

pub fn title_class() -> Class {
  css.class([css.font_weight("500"), css.line_height("1.5")])
}

pub fn description_class() -> Class {
  css.class([css.color(tokens.text_muted), css.line_height("1.5")])
}