Howdy

Hover card

Hover cards: a preview that appears beside a link while the pointer rests on it or it has focus, such as a profile behind a name.

componentimport howdy/ui/hover_cardSince Howdy 2.0
gleam run -m howdy/ui add hover_card

Hover card

Written by @ada.

AL
Ada LovelaceWrites the notes on the engine.

html.p([], [
  text("Written by "),
  html.a([attribute.href("#"), ..ui.hover_card_trigger("example-card")], [
    text("@ada"),
  ]),
  text("."),
  ui.hover_card("example-card", [], [
    ui.row([], [
      ui.avatar_initials("AL"),
      ui.stack([attribute.style("gap", "0.125rem")], [
        html.strong([], [text("Ada Lovelace")]),
        ui.muted("Writes the notes on the engine."),
      ]),
    ]),
  ]),
])
Full source of howdy/ui/hover_card
//// Hover cards: a preview that appears beside a link while the pointer
//// rests on it or it has focus, such as a profile behind a name.
////
//// ```gleam
//// html.a([attribute.href("/people/ada"), ..hover_card.trigger("ada-card")], [text("@ada")]),
//// hover_card.card("ada-card", [], [profile_summary]),
//// ```
////
//// A hover card adds to its link without replacing it: the link still
//// goes where it says, so nothing depends on the card, which touch screens
//// never show. It opens after half a second and stays open while the
//// pointer is over it, so it can hold links of its own. Escape hides it.

import howdy/ui/style.{anchor_name, 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}

/// Attributes for the link the card with this id previews.
pub fn trigger(id: String) -> List(Attribute(msg)) {
  [
    attribute.data("howdy-hover-card", id),
    attribute.data("howdy-anchor", anchor_name(id)),
  ]
}

pub fn card(
  id: String,
  attributes: List(Attribute(msg)),
  children: List(Element(msg)),
) -> Element(msg) {
  html.div(
    [
      class(card_class()),
      attribute.id(id),
      attribute.popover("manual"),
      attribute.data("howdy-anchored", anchor_name(id)),
      ..attributes
    ],
    children,
  )
}

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

pub fn card_class() -> Class {
  css.class([
    css.inset("auto"),
    css.margin_("0.375rem 0"),
    css.property("position-area", "block-end span-inline-end"),
    css.property("position-try-fallbacks", "flip-block, flip-inline"),
    css.property("width", "min(20rem, calc(100vw - 1rem))"),
    css.padding(rem(1.0)),
    css.background(tokens.surface),
    css.color(tokens.text),
    style.bordered(),
    style.radius(tokens.radius_medium),
    css.box_shadow("0 10px 30px -10px rgb(0 0 0 / 0.3)"),
  ])
}