Artists
+ +Artists
+ Create New +There are no artists.
+ {{end}} +diff --git a/admin/accounthttp.go b/admin/accounthttp.go index 1e4742b..634bae6 100644 --- a/admin/accounthttp.go +++ b/admin/accounthttp.go @@ -18,12 +18,12 @@ import ( func accountHandler(app *model.AppState) http.Handler { mux := http.NewServeMux() - mux.Handle("/totp-setup", totpSetupHandler(app)) - mux.Handle("/totp-confirm", totpConfirmHandler(app)) - mux.Handle("/totp-delete/", http.StripPrefix("/totp-delete", totpDeleteHandler(app))) + mux.Handle("/account/totp-setup", totpSetupHandler(app)) + mux.Handle("/account/totp-confirm", totpConfirmHandler(app)) + mux.Handle("/account/totp-delete/", http.StripPrefix("/totp-delete", totpDeleteHandler(app))) - mux.Handle("/password", changePasswordHandler(app)) - mux.Handle("/delete", deleteAccountHandler(app)) + mux.Handle("/account/password", changePasswordHandler(app)) + mux.Handle("/account/delete", deleteAccountHandler(app)) return mux } diff --git a/admin/artisthttp.go b/admin/artisthttp.go index 8c33050..9d99fd4 100644 --- a/admin/artisthttp.go +++ b/admin/artisthttp.go @@ -10,9 +10,9 @@ import ( "arimelody-web/model" ) -func serveArtist(app *model.AppState) http.Handler { +func serveArtists(app *model.AppState) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - slices := strings.Split(r.URL.Path[1:], "/") + slices := strings.Split(strings.TrimPrefix(r.URL.Path, "/artists")[1:], "/") id := slices[0] artist, err := controller.GetArtist(app.DB, id) if err != nil { diff --git a/admin/http.go b/admin/http.go index 136309e..1094095 100644 --- a/admin/http.go +++ b/admin/http.go @@ -47,15 +47,16 @@ func Handler(app *model.AppState) http.Handler { mux.Handle("/register", registerAccountHandler(app)) mux.Handle("/account", requireAccount(accountIndexHandler(app))) - mux.Handle("/account/", requireAccount(http.StripPrefix("/account", accountHandler(app)))) + mux.Handle("/account/", requireAccount(accountHandler(app))) mux.Handle("/logs", requireAccount(logsHandler(app))) - mux.Handle("/release/", requireAccount(http.StripPrefix("/release", serveRelease(app)))) - mux.Handle("/artist/", requireAccount(http.StripPrefix("/artist", serveArtist(app)))) - mux.Handle("/track/", requireAccount(http.StripPrefix("/track", serveTrack(app)))) + mux.Handle("/releases", requireAccount(serveReleases(app))) + mux.Handle("/releases/", requireAccount(serveReleases(app))) + mux.Handle("/artists/", requireAccount(serveArtists(app))) + mux.Handle("/tracks/", requireAccount(serveTracks(app))) - mux.Handle("/static/", http.StripPrefix("/static", staticHandler())) + mux.Handle("/static/", staticHandler()) mux.Handle("/", requireAccount(AdminIndexHandler(app))) @@ -470,7 +471,8 @@ var staticFS embed.FS func staticHandler() http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - file, err := staticFS.ReadFile(filepath.Join("static", filepath.Clean(r.URL.Path))) + uri := strings.TrimPrefix(r.URL.Path, "/static") + file, err := staticFS.ReadFile(filepath.Join("static", filepath.Clean(uri))) if err != nil { http.NotFound(w, r) return diff --git a/admin/releasehttp.go b/admin/releasehttp.go index 991845f..5484609 100644 --- a/admin/releasehttp.go +++ b/admin/releasehttp.go @@ -3,6 +3,7 @@ package admin import ( "fmt" "net/http" + "os" "strings" "arimelody-web/admin/templates" @@ -10,11 +11,52 @@ import ( "arimelody-web/model" ) -func serveRelease(app *model.AppState) http.Handler { +func serveReleases(app *model.AppState) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - slices := strings.Split(r.URL.Path[1:], "/") + slices := strings.Split(strings.TrimPrefix(r.URL.Path, "/releases")[1:], "/") releaseID := slices[0] + var action string = "" + if len(slices) > 1 { + action = slices[1] + } + + if len(releaseID) > 0 { + serveRelease(app, releaseID, action).ServeHTTP(w, r) + return + } + + session := r.Context().Value("session").(*model.Session) + + type ReleasesData struct { + adminPageData + Releases []*model.Release + } + + releases, err := controller.GetAllReleases(app.DB, false, 0, true) + if err != nil { + fmt.Fprintf(os.Stderr, "WARN: Failed to pull releases: %s\n", err) + http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) + return + } + + err = templates.ReleasesTemplate.Execute(w, ReleasesData{ + adminPageData: adminPageData{ + Path: r.URL.Path, + Session: session, + }, + Releases: releases, + }) + if err != nil { + fmt.Fprintf(os.Stderr, "WARN: Failed to render releases page: %s\n", err) + http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) + return + } + }) +} + +func serveRelease(app *model.AppState, releaseID string, action string) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { session := r.Context().Value("session").(*model.Session) release, err := controller.GetRelease(app.DB, releaseID, true) @@ -28,8 +70,8 @@ func serveRelease(app *model.AppState) http.Handler { return } - if len(slices) > 1 { - switch slices[1] { + if len(action) > 0 { + switch action { case "editcredits": serveEditCredits(release).ServeHTTP(w, r) return diff --git a/admin/static/admin.css b/admin/static/admin.css index 7dad27f..ab736f2 100644 --- a/admin/static/admin.css +++ b/admin/static/admin.css @@ -66,6 +66,13 @@ } } +@media (prefers-color-scheme: dark) { + img.icon { + -webkit-filter: invert(1); + filter: invert(1); + } +} + body { width: calc(100% - 180px); height: calc(100vh - 1em); @@ -184,8 +191,9 @@ a:hover { } */ -a img.icon { +img.icon { height: .8em; + transition: filter .1s ease-out; } code { diff --git a/admin/static/edit-artist.js b/admin/static/edit-artist.js index 2ca4c0d..069c25d 100644 --- a/admin/static/edit-artist.js +++ b/admin/static/edit-artist.js @@ -81,7 +81,7 @@ removeAvatarBtn.addEventListener("click", () => { }); document.addEventListener('readystatechange', () => { - document.querySelectorAll('.card#releases .credit').forEach(el => { + document.querySelectorAll('#releases .credit').forEach(el => { hijackClickEvent(el, el.querySelector('.credit-name a')); }); }); diff --git a/admin/static/edit-release.css b/admin/static/edit-release.css index b4fe17b..b8817e0 100644 --- a/admin/static/edit-release.css +++ b/admin/static/edit-release.css @@ -14,6 +14,8 @@ input[type="text"] { border-radius: 8px; background: var(--bg-2); box-shadow: var(--shadow-md); + + transition: background .1s ease-out, color .1s ease-out; } .release-artwork { @@ -31,6 +33,7 @@ input[type="text"] { .release-artwork #remove-artwork { margin-top: .5em; padding: .3em .6em; + background: var(--bg-3); } .release-info { @@ -118,6 +121,7 @@ input[type="text"] { gap: .5em; flex-direction: row; justify-content: right; + color: var(--fg-3); } .release-actions button, @@ -163,7 +167,7 @@ dialog div.dialog-actions { * RELEASE CREDITS */ -.card#credits .credit { +#credits .credit { margin-bottom: .5em; padding: .5em; display: flex; @@ -178,24 +182,24 @@ dialog div.dialog-actions { cursor: pointer; transition: background .1s ease-out; } -.card#credits .credit:hover { +#credits .credit:hover { background-color: var(--bg-1); } -.card#credits .credit p { +#credits .credit p { margin: 0; } -.card#credits .credit .artist-avatar { +#credits .credit .artist-avatar { border-radius: 12px; } -.card#credits .credit .artist-name { +#credits .credit .artist-name { color: var(--fg-3); font-weight: bold; } -.card#credits .credit .artist-role small { +#credits .credit .artist-role small { font-size: inherit; opacity: .66; } @@ -314,33 +318,38 @@ dialog div.dialog-actions { * RELEASE LINKS */ -.card#links ul { +#links ul { padding: 0; display: flex; gap: .2em; } -.card#links a.button:hover { +#links a img.icon { + -webkit-filter: none; + filter: none; +} + +#links a.button:hover { color: var(--bg-3) !important; background-color: var(--fg-3) !important; } -.card#links a.button[data-name="spotify"] { +#links a.button[data-name="spotify"] { color: #101010; background-color: #8cff83 } -.card#links a.button[data-name="apple music"] { +#links a.button[data-name="apple music"] { color: #101010; background-color: #8cd9ff } -.card#links a.button[data-name="soundcloud"] { +#links a.button[data-name="soundcloud"] { color: #101010; background-color: #fdaa6d } -.card#links a.button[data-name="youtube"] { +#links a.button[data-name="youtube"] { color: #101010; background-color: #ff6e6e } @@ -428,7 +437,7 @@ dialog div.dialog-actions { * RELEASE TRACKS */ -.card#tracks .track { +#tracks .track { margin-bottom: 1em; padding: 1em; display: flex; @@ -438,49 +447,51 @@ dialog div.dialog-actions { border-radius: 16px; background: var(--bg-2); box-shadow: var(--shadow-md); + + transition: background .1s ease-out, color .1s ease-out; } -.card#tracks .track h3, -.card#tracks .track p { +#tracks .track h3, +#tracks .track p { margin: 0; } -.card#tracks h2.track-title { +#tracks h2.track-title { margin: 0; display: flex; gap: .5em; } -.card#tracks h2.track-title .track-number { +#tracks h2.track-title .track-number { opacity: .5; } -.card#tracks a:hover { +#tracks a:hover { text-decoration: underline; } -.card#tracks .track-album { +#tracks .track-album { margin-left: auto; font-style: italic; font-size: .75em; opacity: .5; } -.card#tracks .track-album.empty { +#tracks .track-album.empty { color: #ff2020; opacity: 1; } -.card#tracks .track-description { +#tracks .track-description { font-style: italic; } -.card#tracks .track-lyrics { +#tracks .track-lyrics { max-height: 10em; overflow-y: scroll; } -.card#tracks .track .empty { +#tracks .track .empty { opacity: 0.75; } diff --git a/admin/static/edit-release.js b/admin/static/edit-release.js index 5db4bbf..ca2754f 100644 --- a/admin/static/edit-release.js +++ b/admin/static/edit-release.js @@ -100,7 +100,7 @@ removeArtworkBtn.addEventListener("click", () => { }); document.addEventListener("readystatechange", () => { - document.querySelectorAll(".card#credits .credit").forEach(el => { + document.querySelectorAll("#credits .credit").forEach(el => { hijackClickEvent(el, el.querySelector(".artist-name a")); }); }); diff --git a/admin/static/index.js b/admin/static/index.js index c35b596..c6f6b58 100644 --- a/admin/static/index.js +++ b/admin/static/index.js @@ -14,7 +14,7 @@ newReleaseBtn.addEventListener("click", event => { headers: { "Content-Type": "application/json" }, body: JSON.stringify({id}) }).then(res => { - if (res.ok) location = "/admin/release/" + id; + if (res.ok) location = "/admin/releases/" + id; else { res.text().then(err => { alert("Request failed: " + err); @@ -39,7 +39,7 @@ newArtistBtn.addEventListener("click", event => { }).then(res => { res.text().then(text => { if (res.ok) { - location = "/admin/artist/" + id; + location = "/admin/artists/" + id; } else { alert("Request failed: " + text); console.error(text); @@ -63,7 +63,7 @@ newTrackBtn.addEventListener("click", event => { }).then(res => { res.text().then(text => { if (res.ok) { - location = "/admin/track/" + text; + location = "/admin/tracks/" + text; } else { alert("Request failed: " + text); console.error(text); diff --git a/admin/static/release-list-item.css b/admin/static/release-list-item.css index 3481257..aedd121 100644 --- a/admin/static/release-list-item.css +++ b/admin/static/release-list-item.css @@ -51,6 +51,7 @@ .release-actions { margin-top: .5em; user-select: none; + color: var(--fg-3); } .release-actions a { diff --git a/admin/templates/html/artists.html b/admin/templates/html/artists.html new file mode 100644 index 0000000..7b2a464 --- /dev/null +++ b/admin/templates/html/artists.html @@ -0,0 +1,30 @@ +{{define "head"}} +
There are no artists.
+ {{end}} +{{.PrintArtists true true}}
{{.ReleaseType}} - ({{len .Tracks}} track{{if not (eq (len .Tracks) 1)}}s{{end}})
+ ({{len .Tracks}} track{{if not (eq (len .Tracks) 1)}}s{{end}}){{.Release.PrintArtists true true}}
Role: {{.Role}} diff --git a/admin/templates/html/edit-release.html b/admin/templates/html/edit-release.html index 309decf..9a16f65 100644 --- a/admin/templates/html/edit-release.html +++ b/admin/templates/html/edit-release.html @@ -99,10 +99,10 @@
{{.Role}} {{if .Primary}} @@ -130,8 +130,8 @@
{{$Track.GetDescriptionHTML}}
diff --git a/admin/templates/html/layout.html b/admin/templates/html/layout.html index 55f2359..0aaf9ca 100644 --- a/admin/templates/html/layout.html +++ b/admin/templates/html/layout.html @@ -28,14 +28,14 @@music
-