From a8ed5aa8ffc879d5ee4d09f00795111d2598c9ac Mon Sep 17 00:00:00 2001 From: Mikko Ahlroth Date: Sun, 15 Oct 2023 20:23:50 +0300 Subject: [PATCH] Search works --- src/elekf/web/authed_view.gleam | 24 +------------ src/elekf/web/components/library_view.gleam | 35 ++++++++++++++++--- .../library_views/tracks_view.gleam | 13 ++++++- style.css | 17 +++------ 4 files changed, 48 insertions(+), 41 deletions(-) diff --git a/src/elekf/web/authed_view.gleam b/src/elekf/web/authed_view.gleam index cb5ff39..b7d5dea 100644 --- a/src/elekf/web/authed_view.gleam +++ b/src/elekf/web/authed_view.gleam @@ -2,16 +2,12 @@ //// view for the app. import gleam/io -import gleam/int import gleam/list import gleam/option -import gleam/map -import gleam/string import gleam/javascript/promise import lustre/element.{text} -import lustre/element/html.{div, h3, p} +import lustre/element/html.{div, p} import lustre/attribute -import lustre/event import lustre/effect import elekf/web/common.{PlayQueue} import ibroadcast/library/library as library_api @@ -22,7 +18,6 @@ import elekf/library.{Library} import elekf/library/track.{Track} import elekf/transfer/library as library_transfer import elekf/web/components/player -import elekf/web/components/search import elekf/web/components/library_views/tracks_view import elekf/web/events/start_play import elekf/web/utils @@ -48,7 +43,6 @@ pub type Model { library: Library, settings: option.Option(common.Settings), request_config: RequestConfig, - search: search.Model, play_status: PlayStatus, ) } @@ -57,7 +51,6 @@ pub type Msg { UpdateAuthData(common.AuthData) LibraryResult(Result(library_api.ResponseData, http.ResponseError)) PlayerMsg(player.Msg) - Search(search.Msg) StartPlay(PlayQueue, Int) } @@ -68,7 +61,6 @@ pub fn init(auth_data: common.AuthData) { library: library.empty(), settings: option.None, request_config: form_request_config(auth_data), - search: search.init(), play_status: NoTracks, ) @@ -165,17 +157,10 @@ pub fn update(model: Model, msg) { }, ) } - Search(msg) -> { - let search_model = search.update(model.search, msg) - - #(Model(..model, search: search_model), effect.none()) - } } } pub fn view(model: Model) { - let search_text = string.lowercase(model.search.search_text) - div( [attribute.id("authed-view-wrapper")], [ @@ -200,13 +185,6 @@ pub fn view(model: Model) { div( [attribute.id("authed-view-player")], [ - div( - [attribute.id("search-positioner")], - [ - search.view(model.search) - |> element.map(Search), - ], - ), case model.play_status { HasTracks(PlayInfo(player: player, ..)) -> div( diff --git a/src/elekf/web/components/library_view.gleam b/src/elekf/web/components/library_view.gleam index 6946cd6..15b4f7d 100644 --- a/src/elekf/web/components/library_view.gleam +++ b/src/elekf/web/components/library_view.gleam @@ -16,6 +16,7 @@ import elekf/library/album.{Album} import elekf/library/artist.{Artist} import elekf/library/track.{Track} import elekf/web/events/start_play +import elekf/web/components/search /// An item in the library with its ID. pub type LibraryItem(a) = @@ -29,6 +30,13 @@ pub type DataGetter(a) = pub type ItemView(a) = fn(Library, List(LibraryItem(a)), Int, LibraryItem(a)) -> element.Element(Msg) +/// A filter that gets the item and the current search string and must return +/// `True` if the item should be shown and `False` if not. +/// +/// The search string is lowercased. +pub type SearchFilter(a) = + fn(a, String) -> Bool + /// Shuffler takes all of the items, finds all of the tracks in them, and /// shuffles them for playback. pub type Shuffler(a) = @@ -53,6 +61,7 @@ pub type Msg { LibraryUpdated(Library) ShuffleAll StartPlay(List(LibraryItem(Track)), Int) + Search(search.Msg) } pub type Model(a) { @@ -61,6 +70,7 @@ pub type Model(a) { data: List(LibraryItem(a)), data_getter: DataGetter(a), shuffler: Shuffler(a), + search: search.Model, ) } @@ -78,12 +88,13 @@ pub fn register( data_getter: DataGetter(a), item_view: ItemView(a), shuffler: Shuffler(a), + search_filter: SearchFilter(a), ) { lustre.component( name, fn() { init(library.empty(), data_getter, shuffler) }, update, - generate_view(item_view), + generate_view(item_view, search_filter), map.from_list([#("library", library_decode)]), ) } @@ -102,7 +113,10 @@ pub fn render( } fn init(library, data_getter, shuffler) { - #(Model(library, data_getter(library), data_getter, shuffler), effect.none()) + #( + Model(library, data_getter(library), data_getter, shuffler, search.init()), + effect.none(), + ) } fn update(model, msg) { @@ -113,15 +127,28 @@ fn update(model, msg) { ) ShuffleAll -> #(model, shuffle_all(model)) StartPlay(tracks, position) -> #(model, start_play.emit(tracks, position)) + Search(search_msg) -> { + let search_model = search.update(model.search, search_msg) + #(Model(..model, search: search_model), effect.none()) + } } } -fn generate_view(item_view: ItemView(a)) { +fn generate_view(item_view: ItemView(a), search_filter: SearchFilter(a)) { fn(model: Model(a)) { + let items = case model.search.search_text { + "" -> model.data + txt -> + model.data + |> list.filter(fn(item) { search_filter(item.1, txt) }) + } + div( [attribute.class("library-list")], list.append( [ + search.view(model.search) + |> element.map(Search), div( [ attribute.class("library-item library-list-shuffle-all"), @@ -131,7 +158,7 @@ fn generate_view(item_view: ItemView(a)) { ), ], list.index_map( - model.data, + items, fn(i, item) { item_view(model.library, model.data, i, item) }, ), ), diff --git a/src/elekf/web/components/library_views/tracks_view.gleam b/src/elekf/web/components/library_views/tracks_view.gleam index 2a87679..5657881 100644 --- a/src/elekf/web/components/library_views/tracks_view.gleam +++ b/src/elekf/web/components/library_views/tracks_view.gleam @@ -1,5 +1,6 @@ //// A library view to all of the tracks in the library. +import gleam/string import gleam/int import gleam/list import gleam/map @@ -15,7 +16,13 @@ const component_name = "tracks-view" /// Register the tracks view as a custom element. pub fn register() { - library_view.register(component_name, data_getter, item_view, shuffler) + library_view.register( + component_name, + data_getter, + item_view, + shuffler, + search_filter, + ) } /// Render the tracks view. @@ -31,6 +38,10 @@ fn shuffler(items) { list.shuffle(items) } +fn search_filter(item: Track, search_text: String) { + string.contains(item.title_lower, search_text) +} + fn item_view( library: Library, items: List(LibraryItem(Track)), diff --git a/style.css b/style.css index 0ebd50d..5e5694d 100644 --- a/style.css +++ b/style.css @@ -30,17 +30,12 @@ main { overflow-y: auto; } -#player { -} - -#search-positioner { - position: relative; -} - #search-bar { position: absolute; - transform: translateY(-200%); - width: 100%; + bottom: 100px; + left: 50%; + transform: translateX(-50%); + width: calc(100vw - 20px); display: flex; flex-direction: row; @@ -49,10 +44,6 @@ main { gap: 10px; } -#search-bar button { - justify-self: flex-end; -} - #search-bar-input-wrapper { flex: 1 1; }