Add search line

This commit is contained in:
Lily Rose 2025-07-17 21:38:41 +10:00
parent e9af37edf7
commit 55fa306b3c

View file

@ -46,9 +46,20 @@ pub fn main() {
Nil Nil
} }
type GeofeedSearchItem {
GeofeedSearchItem(
cidr: String,
country: String,
region: String,
city: String,
postcode: String,
)
}
type Model { type Model {
Model( Model(
geofeed_form: GeofeedForm, geofeed_form: GeofeedForm,
search_item: GeofeedSearchItem,
show_postcode: Bool, show_postcode: Bool,
saving: Bool, saving: Bool,
errors: List(String), errors: List(String),
@ -56,8 +67,16 @@ type Model {
} }
fn init(geofeed_form: GeofeedForm) -> #(Model, Effect(Msg)) { fn init(geofeed_form: GeofeedForm) -> #(Model, Effect(Msg)) {
let search_item =
GeofeedSearchItem(cidr: "", country: "", region: "", city: "", postcode: "")
let model = let model =
Model(geofeed_form:, show_postcode: False, saving: False, errors: []) Model(
geofeed_form:,
search_item:,
show_postcode: False,
saving: False,
errors: [],
)
#(model, effect.none()) #(model, effect.none())
} }
@ -69,6 +88,7 @@ type Msg {
UserMovedItemDown(index: Int) UserMovedItemDown(index: Int)
UserDeletedItem(index: Int) UserDeletedItem(index: Int)
UserUpdatedItem(index: Int, item: GeofeedFormItem) UserUpdatedItem(index: Int, item: GeofeedFormItem)
UserUpdatedSearchItem(search_item: GeofeedSearchItem)
UserSetShowPostcode(show_postcode: Bool) UserSetShowPostcode(show_postcode: Bool)
} }
@ -228,6 +248,9 @@ fn update(model: Model, msg: Msg) -> #(Model, Effect(Msg)) {
}) })
#(Model(..model, geofeed_form:), effect.none()) #(Model(..model, geofeed_form:), effect.none())
} }
UserUpdatedSearchItem(search_item:) -> {
#(Model(..model, search_item:), effect.none())
}
UserSetShowPostcode(show_postcode:) -> { UserSetShowPostcode(show_postcode:) -> {
#(Model(..model, show_postcode:), effect.none()) #(Model(..model, show_postcode:), effect.none())
} }
@ -265,6 +288,8 @@ fn form_button(
} }
fn view(model: Model) -> Element(Msg) { fn view(model: Model) -> Element(Msg) {
let Model(geofeed_form:, search_item:, show_postcode:, saving:, errors:) =
model
element.fragment([ element.fragment([
html.h1( html.h1(
[ [
@ -304,10 +329,10 @@ fn view(model: Model) -> Element(Msg) {
), ),
html.div( html.div(
[attribute.styles([#("display", "flex"), #("justify-content", "center")])], [attribute.styles([#("display", "flex"), #("justify-content", "center")])],
[view_geofeed_form(model.geofeed_form, model.show_postcode)], [view_geofeed_form(geofeed_form:, search_item:, show_postcode:)],
), ),
element.fragment( element.fragment(
model.errors errors
|> list.map(fn(error) { |> list.map(fn(error) {
html.div( html.div(
[ [
@ -334,7 +359,7 @@ fn view(model: Model) -> Element(Msg) {
], ],
[ [
form_button(on_click_msg: UserAddedItem(None), text: "Add"), form_button(on_click_msg: UserAddedItem(None), text: "Add"),
form_button(on_click_msg: UserSavedList, text: case model.saving { form_button(on_click_msg: UserSavedList, text: case saving {
True -> "Saving..." True -> "Saving..."
False -> "Save" False -> "Save"
}), }),
@ -361,26 +386,9 @@ fn view(model: Model) -> Element(Msg) {
]) ])
} }
fn view_geofeed_form( fn input(
geofeed_form: GeofeedForm, value value: String,
show_postcode: Bool, is_valid is_valid: Bool,
) -> Element(Msg) {
case geofeed_form {
[] -> html.p([], [html.text("No items in your geofeed yet.")])
_ -> {
let total = list.length(geofeed_form)
html.ol(
[attribute.styles([#("margin", "0"), #("padding", "0")])],
list.index_map(geofeed_form, fn(item, index) {
html.li([], [view_geofeed_item(item, index, total, show_postcode)])
}),
)
}
}
}
fn form_field_input(
form_field form_field: FormField(a),
chars chars: Int, chars chars: Int,
set_max_length set_max_length: Bool, set_max_length set_max_length: Bool,
placeholder placeholder: String, placeholder placeholder: String,
@ -394,13 +402,13 @@ fn form_field_input(
default_font_size_style, default_font_size_style,
border_style, border_style,
border_radius_style, border_radius_style,
..case form_field.parsed_value { ..case is_valid {
Ok(_) -> [] True -> []
Error(_) -> [shared.error_font_color_style] False -> [shared.error_font_color_style]
} }
]), ]),
attribute.placeholder(placeholder), attribute.placeholder(placeholder),
attribute.value(form_field.raw_value), attribute.value(value),
event.on_input(on_input_handler), event.on_input(on_input_handler),
..case set_max_length { ..case set_max_length {
True -> [attribute.maxlength(chars)] True -> [attribute.maxlength(chars)]
@ -409,6 +417,170 @@ fn form_field_input(
]) ])
} }
fn form_field_input(
form_field form_field: FormField(a),
chars chars: Int,
set_max_length set_max_length: Bool,
placeholder placeholder: String,
on_input_handler on_input_handler: fn(String) -> Msg,
) {
input(
value: form_field.raw_value,
is_valid: result.is_ok(form_field.parsed_value),
chars:,
set_max_length:,
placeholder:,
on_input_handler:,
)
}
fn field_search(
value value: String,
form_field form_field: FormField(a),
) -> Bool {
value == ""
|| string.contains(
does: string.lowercase(form_field.raw_value),
contain: string.lowercase(value),
)
}
fn item_search(
search_item search_item: GeofeedSearchItem,
item item: GeofeedFormItem,
) -> Bool {
field_search(value: search_item.cidr, form_field: item.cidr)
&& field_search(value: search_item.country, form_field: item.country)
&& field_search(value: search_item.region, form_field: item.region)
&& field_search(value: search_item.city, form_field: item.city)
&& field_search(value: search_item.postcode, form_field: item.postcode)
}
fn view_geofeed_form(
geofeed_form geofeed_form: GeofeedForm,
search_item search_item: GeofeedSearchItem,
show_postcode show_postcode: Bool,
) -> Element(Msg) {
case geofeed_form {
[] ->
html.p([attribute.styles([text_align_center_style])], [
html.text("No items in your geofeed yet."),
])
_ -> {
let total = list.length(geofeed_form)
html.div([], [
html.div(
[
attribute.styles([
#("margin", "1em 0"),
#("display", "flex"),
#("gap", "0.6em"),
]),
],
[
input(
value: search_item.cidr,
is_valid: True,
chars: 43,
set_max_length: True,
placeholder: "CIDR",
on_input_handler: fn(value) {
UserUpdatedSearchItem(
GeofeedSearchItem(
..search_item,
cidr: string.lowercase(value),
),
)
},
),
input(
value: search_item.country,
is_valid: True,
chars: 2,
set_max_length: True,
placeholder: "CC",
on_input_handler: fn(value) {
UserUpdatedSearchItem(
GeofeedSearchItem(
..search_item,
country: string.uppercase(value),
),
)
},
),
input(
value: search_item.region,
is_valid: True,
chars: 6,
set_max_length: True,
placeholder: "Region",
on_input_handler: fn(value) {
UserUpdatedSearchItem(
GeofeedSearchItem(
..search_item,
region: string.uppercase(value),
),
)
},
),
input(
value: search_item.city,
is_valid: True,
chars: 24,
set_max_length: False,
placeholder: "City",
on_input_handler: fn(value) {
UserUpdatedSearchItem(
GeofeedSearchItem(..search_item, city: value),
)
},
),
..case show_postcode {
True -> [
input(
value: search_item.postcode,
is_valid: True,
chars: 10,
set_max_length: False,
placeholder: "Postcode",
on_input_handler: fn(value) {
UserUpdatedSearchItem(
GeofeedSearchItem(..search_item, postcode: value),
)
},
),
]
False -> []
}
],
),
case list.any(geofeed_form, item_search(search_item:, item: _)) {
True ->
html.ol(
[attribute.styles([#("margin", "0"), #("padding", "0")])],
list.index_map(geofeed_form, fn(item, index) {
html.li(
[
attribute.value(int.to_string(index + 1)),
..case item_search(search_item:, item:) {
True -> []
False -> [attribute.styles([#("display", "none")])]
}
],
[view_geofeed_item(item:, index:, total:, show_postcode:)],
)
}),
)
False ->
html.p([attribute.styles([text_align_center_style])], [
html.text("Search returned no results."),
])
},
])
}
}
}
fn item_button( fn item_button(
on_click_msg on_click_msg: Msg, on_click_msg on_click_msg: Msg,
disabled disabled: Bool, disabled disabled: Bool,
@ -446,10 +618,10 @@ fn item_button(
} }
fn view_geofeed_item( fn view_geofeed_item(
item: GeofeedFormItem, item item: GeofeedFormItem,
index: Int, index index: Int,
total: Int, total total: Int,
show_postcode: Bool, show_postcode show_postcode: Bool,
) -> Element(Msg) { ) -> Element(Msg) {
let item_buttons = [ let item_buttons = [
item_button( item_button(