diff --git a/web/src/at_record_web/pages/add.gleam b/web/src/at_record_web/pages/add.gleam index e365646..9d0ec0b 100644 --- a/web/src/at_record_web/pages/add.gleam +++ b/web/src/at_record_web/pages/add.gleam @@ -16,7 +16,7 @@ import at_record_web/ui/forms as frm import at_record_web/ui/record_detail as rd import gleam/int import gleam/list -import gleam/option +import gleam/option.{None, Some} import gleam/string import lustre/attribute as attr import lustre/element.{type Element, text} @@ -138,15 +138,12 @@ fn suggestion_row(r: DiscogsResult) -> Element(Msg) { [r.year |> option.map(int.to_string), r.format] |> option.values |> string.join(" · ") - html.li([], [ - html.button([attr.type_("button"), event.on_click(UseDiscogs(r))], [ - cov.thumb(r.thumb_url), - html.div([attr.class("suggestion__main")], [ - html.strong([], [text(r.title)]), - html.div([attr.class("item-meta")], [text(r.artist <> " · " <> meta)]), - ]), - ]), - ]) + frm.suggestion_row( + UseDiscogs(r), + Some(cov.thumb(r.thumb_url)), + r.title, + Some(r.artist <> " · " <> meta), + ) } /// Type an artist name, get Discogs suggestions; picking one locks the @@ -164,12 +161,5 @@ fn artist_autocomplete(model: Model) -> Element(Msg) { } fn artist_suggestion_row(a: ArtistHit) -> Element(Msg) { - html.li([], [ - html.button([attr.type_("button"), event.on_click(UseArtist(a))], [ - cov.thumb(a.thumb_url), - html.div([attr.class("suggestion__main")], [ - html.strong([], [text(a.name)]), - ]), - ]), - ]) + frm.suggestion_row(UseArtist(a), Some(cov.thumb(a.thumb_url)), a.name, None) } diff --git a/web/src/at_record_web/plural.gleam b/web/src/at_record_web/plural.gleam new file mode 100644 index 0000000..e497507 --- /dev/null +++ b/web/src/at_record_web/plural.gleam @@ -0,0 +1,12 @@ +//// Count-noun phrasing shared wherever the UI says "N things". + +import gleam/int + +/// "1 crate", "3 crates"; regular English plurals only, which is all the +/// UI's nouns need. +pub fn count_noun(count: Int, singular: String) -> String { + case count { + 1 -> "1 " <> singular + n -> int.to_string(n) <> " " <> singular <> "s" + } +} diff --git a/web/src/at_record_web/ui/forms.gleam b/web/src/at_record_web/ui/forms.gleam index ad956a4..a0cb9c3 100644 --- a/web/src/at_record_web/ui/forms.gleam +++ b/web/src/at_record_web/ui/forms.gleam @@ -2,6 +2,7 @@ //// labels, and segmented toggles. import gleam/list +import gleam/option import lustre/attribute as attr import lustre/element.{type Element, text} import lustre/element/html @@ -63,6 +64,28 @@ pub fn suggestions(items: List(a), row: fn(a) -> Element(msg)) -> Element(msg) { } } +/// One pickable row for a `suggestions` dropdown: optional leading element +/// (a thumb), a bold title, optional meta line. Every dropdown row in the +/// app is this shape; build variations here, not at call sites. +pub fn suggestion_row( + on_pick: msg, + leading: option.Option(Element(msg)), + title: String, + meta: option.Option(String), +) -> Element(msg) { + html.li([], [ + html.button([attr.type_("button"), event.on_click(on_pick)], [ + leading |> option.unwrap(element.none()), + html.div([attr.class("suggestion__main")], [ + html.strong([], [text(title)]), + meta + |> option.map(fn(m) { html.div([attr.class("item-meta")], [text(m)]) }) + |> option.unwrap(element.none()), + ]), + ]), + ]) +} + pub fn section_label(label: String) -> Element(msg) { html.p([attr.class("section-label")], [text(label)]) }