Search works
This commit is contained in:
parent
bf31c2fd87
commit
a8ed5aa8ff
4 changed files with 48 additions and 41 deletions
|
@ -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(
|
||||
|
|
|
@ -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) },
|
||||
),
|
||||
),
|
||||
|
|
|
@ -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)),
|
||||
|
|
17
style.css
17
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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue