Initial real routing work
This commit is contained in:
parent
22f8574973
commit
7b3e06beb3
4 changed files with 155 additions and 57 deletions
|
@ -6,12 +6,12 @@ import gleam/list
|
|||
import gleam/option
|
||||
import gleam/float
|
||||
import gleam/int
|
||||
import gleam/result
|
||||
import gleam/javascript/promise
|
||||
import lustre/element.{text}
|
||||
import lustre/element/html.{div, nav, p}
|
||||
import lustre/attribute
|
||||
import lustre/effect
|
||||
import lustre/event
|
||||
import birl
|
||||
import ibroadcast/library/library as library_api
|
||||
import ibroadcast/authed_request.{type RequestConfig, RequestConfig}
|
||||
|
@ -23,6 +23,7 @@ import elekf/library.{type Library}
|
|||
import elekf/library/artist.{type Artist}
|
||||
import elekf/library/track.{type Track}
|
||||
import elekf/transfer/library as library_transfer
|
||||
import elekf/web/router
|
||||
import elekf/web/components/player
|
||||
import elekf/web/components/library_item.{type LibraryItem}
|
||||
import elekf/web/components/library_view
|
||||
|
@ -31,7 +32,7 @@ import elekf/web/components/library_views/artists_view
|
|||
import elekf/web/components/library_views/albums_view
|
||||
import elekf/web/components/library_views/single_artist_view
|
||||
import elekf/web/components/button_group
|
||||
import elekf/web/components/button
|
||||
import elekf/web/components/link
|
||||
import elekf/web/events/start_play
|
||||
import elekf/web/events/show_artist
|
||||
import elekf/web/utils
|
||||
|
@ -69,7 +70,7 @@ pub type Model {
|
|||
settings: option.Option(common.Settings),
|
||||
request_config: RequestConfig,
|
||||
play_status: PlayStatus,
|
||||
view_stack: List(library_view.View),
|
||||
view: library_view.View,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -78,8 +79,7 @@ pub type Msg {
|
|||
LibraryResult(Result(library_api.ResponseData, http.ResponseError))
|
||||
PlayerMsg(player.Msg)
|
||||
StartPlay(PlayQueue, Int)
|
||||
ShowArtist(LibraryItem(Artist))
|
||||
ChangeView(library_view.View)
|
||||
Router(router.Msg)
|
||||
}
|
||||
|
||||
pub fn init(auth_data: common.AuthData) {
|
||||
|
@ -90,10 +90,14 @@ pub fn init(auth_data: common.AuthData) {
|
|||
settings: option.None,
|
||||
request_config: form_request_config(auth_data),
|
||||
play_status: NoTracks,
|
||||
view_stack: [library_view.Tracks],
|
||||
view: library_view.Tracks,
|
||||
)
|
||||
|
||||
#(model, load_library(model))
|
||||
let router_effect =
|
||||
effect.from(fn(dispatch) { router.init(dispatch) })
|
||||
|> effect.map(Router)
|
||||
|
||||
#(model, effect.batch([load_library(model), router_effect]))
|
||||
}
|
||||
|
||||
pub fn update(model: Model, msg) {
|
||||
|
@ -144,15 +148,6 @@ pub fn update(model: Model, msg) {
|
|||
let #(status, effect) = handle_start_play(model, tracks, position)
|
||||
#(Model(..model, play_status: status), effect)
|
||||
}
|
||||
ShowArtist(artist) -> #(
|
||||
Model(
|
||||
..model,
|
||||
view_stack: list.append(model.view_stack, [
|
||||
library_view.SingleArtist(artist),
|
||||
]),
|
||||
),
|
||||
effect.none(),
|
||||
)
|
||||
PlayerMsg(player.NextTrack) | PlayerMsg(player.PrevTrack) -> {
|
||||
if_player(model, fn(info) {
|
||||
let next_index = case msg {
|
||||
|
@ -187,8 +182,9 @@ pub fn update(model: Model, msg) {
|
|||
)
|
||||
})
|
||||
}
|
||||
ChangeView(view) -> {
|
||||
#(Model(..model, view_stack: [view]), effect.none())
|
||||
Router(router.RouteChanged(route)) -> {
|
||||
let view = result.unwrap(route_to_view(route), library_view.Tracks)
|
||||
#(Model(..model, view: view), effect.none())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -209,19 +205,18 @@ pub fn view(model: Model) {
|
|||
div([attribute.id("authed-view-library")], [
|
||||
nav([attribute.id("library-top-nav")], [
|
||||
button_group.view("", [], [
|
||||
button.view("", [event.on_click(ChangeView(library_view.Tracks))], [
|
||||
link.view(router.to_hash(router.TrackList), "", [], [
|
||||
icon("music-note-beamed", Alt("Tracks")),
|
||||
]),
|
||||
button.view("", [event.on_click(ChangeView(library_view.Artists))], [
|
||||
link.view(router.to_hash(router.ArtistList), "", [], [
|
||||
icon("file-person", Alt("Artists")),
|
||||
]),
|
||||
button.view("", [event.on_click(ChangeView(library_view.Albums))], [
|
||||
link.view(router.to_hash(router.AlbumList), "", [], [
|
||||
icon("disc", Alt("Albums")),
|
||||
]),
|
||||
]),
|
||||
]),
|
||||
..list.map(model.view_stack, fn(view) {
|
||||
case view {
|
||||
case model.view {
|
||||
library_view.Tracks ->
|
||||
tracks_view.render(model.library, model.settings, [
|
||||
attribute.id("tracks-view"),
|
||||
|
@ -232,7 +227,6 @@ pub fn view(model: Model) {
|
|||
artists_view.render(model.library, model.settings, [
|
||||
attribute.id("artists-view"),
|
||||
attribute.class("glass-bg"),
|
||||
show_artist.on(ShowArtist),
|
||||
])
|
||||
library_view.Albums ->
|
||||
albums_view.render(model.library, model.settings, [
|
||||
|
@ -241,18 +235,12 @@ pub fn view(model: Model) {
|
|||
start_play.on(StartPlay),
|
||||
])
|
||||
library_view.SingleArtist(artist_info) ->
|
||||
single_artist_view.render(
|
||||
model.library,
|
||||
artist_info,
|
||||
model.settings,
|
||||
[
|
||||
single_artist_view.render(model.library, artist_info, model.settings, [
|
||||
attribute.id("single-artist-view"),
|
||||
attribute.class("glass-bg"),
|
||||
start_play.on(StartPlay),
|
||||
],
|
||||
)
|
||||
}
|
||||
})
|
||||
])
|
||||
},
|
||||
]),
|
||||
div(
|
||||
[
|
||||
|
@ -388,3 +376,11 @@ fn maybe_send_history_status(play_info: PlayInfo, request_config: RequestConfig)
|
|||
HistorySent -> play_info
|
||||
}
|
||||
}
|
||||
|
||||
fn route_to_view(route: router.Route) {
|
||||
case route {
|
||||
router.TrackList -> Ok(library_view.Tracks)
|
||||
router.ArtistList -> Ok(library_view.Artists)
|
||||
router.AlbumList -> Ok(library_view.Albums)
|
||||
}
|
||||
}
|
||||
|
|
19
src/elekf/web/components/link.gleam
Normal file
19
src/elekf/web/components/link.gleam
Normal file
|
@ -0,0 +1,19 @@
|
|||
import lustre/attribute
|
||||
import lustre/element
|
||||
import lustre/element/html.{a}
|
||||
|
||||
pub fn view(
|
||||
href: String,
|
||||
class: String,
|
||||
extra_attributes: List(attribute.Attribute(a)),
|
||||
content: List(element.Element(a)),
|
||||
) {
|
||||
a(
|
||||
[
|
||||
attribute.href(href),
|
||||
attribute.class("glass-button " <> class),
|
||||
..extra_attributes
|
||||
],
|
||||
content,
|
||||
)
|
||||
}
|
76
src/elekf/web/router.gleam
Normal file
76
src/elekf/web/router.gleam
Normal file
|
@ -0,0 +1,76 @@
|
|||
import gleam/int
|
||||
import gleam/string
|
||||
import gleam/result
|
||||
import plinth/browser/window
|
||||
|
||||
const artists = "artists"
|
||||
|
||||
const albums = "albums"
|
||||
|
||||
const settings = "settings"
|
||||
|
||||
pub type Msg {
|
||||
RouteChanged(route: Route)
|
||||
}
|
||||
|
||||
pub type Route {
|
||||
TrackList
|
||||
ArtistList
|
||||
AlbumList
|
||||
Artist(id: Int)
|
||||
Album(id: Int)
|
||||
Settings
|
||||
}
|
||||
|
||||
pub fn init(dispatch: fn(Msg) -> Nil) {
|
||||
window.add_event_listener("hashchange", fn(_e) {
|
||||
let _ = run(dispatch)
|
||||
Nil
|
||||
})
|
||||
}
|
||||
|
||||
pub fn run(dispatch: fn(Msg) -> Nil) {
|
||||
use hash <- result.try(window.get_hash())
|
||||
use route <- result.try(parse(hash))
|
||||
Ok(dispatch(RouteChanged(route)))
|
||||
}
|
||||
|
||||
pub fn to_hash(route: Route) {
|
||||
"#" <> to_string(route)
|
||||
}
|
||||
|
||||
fn parse(route: String) {
|
||||
let parts =
|
||||
route
|
||||
|> string.drop_left(1)
|
||||
|> string.split("/")
|
||||
|
||||
case parts {
|
||||
[""] -> Ok(TrackList)
|
||||
[a] if a == artists -> Ok(ArtistList)
|
||||
[a] if a == albums -> Ok(AlbumList)
|
||||
[a, id] -> {
|
||||
case a, int.parse(id) {
|
||||
a, Ok(id) if a == artists -> Ok(Artist(id))
|
||||
a, Ok(id) if a == albums -> Ok(Album(id))
|
||||
_, _ -> Error(Nil)
|
||||
}
|
||||
}
|
||||
[s] if s == settings -> Ok(Settings)
|
||||
|
||||
_ -> Error(Nil)
|
||||
}
|
||||
}
|
||||
|
||||
fn to_string(route: Route) {
|
||||
let parts = case route {
|
||||
TrackList -> []
|
||||
ArtistList -> [artists]
|
||||
AlbumList -> [albums]
|
||||
Artist(id) -> [artists, int.to_string(id)]
|
||||
Album(id) -> [albums, int.to_string(id)]
|
||||
Settings -> [settings]
|
||||
}
|
||||
|
||||
"/" <> string.join(parts, "/")
|
||||
}
|
13
style.css
13
style.css
|
@ -70,6 +70,10 @@
|
|||
|
||||
.glass-button {
|
||||
border-radius: var(--button-border-radius);
|
||||
|
||||
text-align: center;
|
||||
color: var(--text-color);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.button-small,
|
||||
|
@ -89,6 +93,10 @@
|
|||
align-items: stretch;
|
||||
}
|
||||
|
||||
.button-group > * {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.button-group .glass-button {
|
||||
border-radius: 0;
|
||||
border-right: none;
|
||||
|
@ -296,10 +304,9 @@ single-artist-view {
|
|||
height: 100%;
|
||||
}
|
||||
|
||||
#library-top-nav button {
|
||||
display: block;
|
||||
width: 100%;
|
||||
#library-top-nav .glass-button {
|
||||
font-size: 2rem;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#search-bar {
|
||||
|
|
Loading…
Reference in a new issue