From 94fce03750bd24a77ca1827a6ad44aea1f052e4a Mon Sep 17 00:00:00 2001 From: Cadence Ember Date: Mon, 7 Apr 2025 09:41:30 +1200 Subject: [PATCH] Polishing --- public/player-marker.js | 3 ++- pug/album_grid.pug | 4 +++- pug/includes/layout.pug | 35 ++++++++++++++++++++++++++++++----- pug/includes/tag-status.pug | 4 ++-- pug/player.pug | 4 ++-- pug/track_list.pug | 2 +- routes/app.js | 10 +++++----- routes/play.js | 5 +++-- 8 files changed, 48 insertions(+), 19 deletions(-) diff --git a/public/player-marker.js b/public/player-marker.js index ade80ce..bcc6716 100644 --- a/public/player-marker.js +++ b/public/player-marker.js @@ -3,8 +3,9 @@ function movePlayer() { const playerExists = pc.querySelector("iframe") if (!playerExists) return const pm = document.getElementById("player-marker") + pm.style.display = "block" pm.style.height = `${pc.clientHeight}px` pc.style.top = `${Math.round(pm.getBoundingClientRect().top)}px` } movePlayer() -document.body.addEventListener("htmx:afterSettle", movePlayer) +document.body.addEventListener("htmx:load", movePlayer) diff --git a/pug/album_grid.pug b/pug/album_grid.pug index b1eb679..3771bd1 100644 --- a/pug/album_grid.pug +++ b/pug/album_grid.pug @@ -9,7 +9,9 @@ block view each item in items div a.s-link.album-grid-link(href=`/api/play/${item.item_type}/${item.item_id}` hx-target="#player" hx-select="#player" hx-indicator="null" hx-push-url="false") - img(loading="lazy" src=item.item_art_url width=210 height=210) + .ps-relative + img(loading="lazy" src=item.item_art_url width=210 height=210) + .album-grid-link__play!= icons.get("play-solid", 64) p.fs-body3.mb8= item.item_title .d-flex.fw-wrap.g4 if item.why diff --git a/pug/includes/layout.pug b/pug/includes/layout.pug index 392a69d..1ac9ca5 100644 --- a/pug/includes/layout.pug +++ b/pug/includes/layout.pug @@ -25,6 +25,9 @@ html script(defer src="/static/player-marker.js") meta(name="htmx-config" content='{"requestClass":"is-loading"}') style. + .ws340 { + width: 340px; + } .themed { --theme-base-primary-color-h: 191; --theme-base-primary-color-s: 37%; @@ -61,6 +64,28 @@ html .album-grid-link { --_li-fc: var(--black); --_li-fc-visited: var(--black-400); + display: block; + } + .album-grid-link__play { + pointer-events: none; + position: absolute; + color: #000; + opacity: 0; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + transition: 1s ease-out; + } + .album-grid-link img { + transition: 1s ease-out; + } + .album-grid-link:hover img { + transition: 2s ease-out 0.7s; + opacity: 0.3; + } + .album-grid-link:hover .album-grid-link__play { + transition: 2s ease-out 0.7s; + opacity: 1; } .wc-hl { cursor: pointer; @@ -71,7 +96,7 @@ html flex-shrink: 0; } body.themed.theme-system.overflow-y-scroll(hx-boost="true" hx-swap="outerHTML" hx-target="#page" hx-select="#page") - #page + #page(hx-history-elt) header.s-topbar.ps-sticky.t0 .s-topbar--container.wmx9 .s-topbar--logo @@ -97,8 +122,8 @@ html main.fl-grow1 block view - aside.ws3 - .ps-sticky.d-flex.fd-column.g12(style="top: 80px") + aside.ws340 + .ps-fixed.ws340.d-flex.fd-column.g12(style="top: 80px") if arrange === "tag" include tag-status.pug @@ -120,7 +145,7 @@ html input(type="hidden" name="shape" value=shape) button.s-btn.s-btn__xs.s-btn__icon.s-btn__outlined.s-btn__muted#search-submit(style="height: 38px")!= icons.get("search") - #player-marker.pe-none.myn6 + #player-marker.pe-none(style="display: none") .s-sidebarwidget .s-sidebarwidget--header Collection @@ -177,5 +202,5 @@ html .s-progress--bar.bg-orange-400(title=`${count.taste[2]} labels with 200-1999 fans`)= count.taste[2] .s-progress--bar.bg-red-400(title=`${count.taste[3]} labels with >2000 fans`)= count.taste[3] - #player-container.ps-fixed.r16.ws3(hx-preserve="true") + #player-container.ps-fixed.r16.ws340(hx-preserve="true") #player diff --git a/pug/includes/tag-status.pug b/pug/includes/tag-status.pug index ac10009..ec30bca 100644 --- a/pug/includes/tag-status.pug +++ b/pug/includes/tag-status.pug @@ -1,14 +1,14 @@ if downloader.total > 0 || downloader.outcome #tag-download if !downloader.running && !downloader.outcome - form.s-notice.s-notice__info.d-flex.ai-center.p8.gx16.pl16(role="status" hx-target="#tag-download" hx-post="/api/tag-download") + form.s-notice.s-notice__info.d-flex.ai-center.p8.gx16.pl16(role="status" hx-target="#tag-download" hx-select="#tag-download" hx-post="/api/tag-download") != icons.get("info-circle") div Tag data needs to be downloaded. This will take a while. input(type="hidden" name="account" value=account) button.s-btn.s-btn__outlined Download now else if !downloader.outcome - .s-notice.p16(role="status" hx-target="#tag-download" hx-get=`/api/tag-download?account=${account}` hx-trigger="every 5s" hx-indicator="null") + .s-notice.p16(role="status" hx-target="#tag-download" hx-select="#tag-download" hx-get=`/api/tag-download?account=${account}` hx-trigger="every 5s" hx-indicator="null") .d-flex.gx16.ai-center != icons.get("cloud-download") .fl-grow1 Downloading tags... diff --git a/pug/player.pug b/pug/player.pug index 7750297..48e7e21 100644 --- a/pug/player.pug +++ b/pug/player.pug @@ -1,5 +1,5 @@ #player .s-sidebarwidget(style="overflow: hidden") div(style="margin: -1px; margin-bottom: -11px").ps-relative - a.ps-absolute.bg-white.bar0.t0.r0.s-btn.s-btn__icon.s-btn__muted.s-btn__sm.px16(href=`/api/play/${item_type}/${item_id}` hx-target="#player" hx-select="#player" hx-push-url="false").fc-theme-primary!= icons.get("refresh-double") - iframe(style="border: 0; width: 100%; height: 424px;" src=`https://bandcamp.com/EmbeddedPlayer/${item_type}=${item_id}/size=large/bgcol=ffffff/linkcol=63b2cc/artwork=none/transparent=true/`) + a.ps-absolute.bg-white.bar0.t0.r0.s-btn.s-btn__icon.s-btn__muted.s-btn__sm.px12(href=`/api/play/${item_type}/${item_id}` hx-target="#player" hx-select="#player" hx-push-url="false").fc-theme-primary!= icons.get("refresh-double", 18) + iframe(style="border: 0; width: 100%; height: 424px;" src=`https://bandcamp.com/EmbeddedPlayer/${item_type}=${item_id}/size=large/bgcol=ffffff/linkcol=63b2cc/artwork=none/transparent=true/track=${track_id}`) diff --git a/pug/track_list.pug b/pug/track_list.pug index 32700f3..d82cdf5 100644 --- a/pug/track_list.pug +++ b/pug/track_list.pug @@ -21,7 +21,7 @@ block view | ☆ else = item.track_number || "-" - td: a(href=`/api/play/${item.item_type}/${item.item_id}` hx-target="#player" hx-select="#player" hx-indicator="null" hx-push-url="false")= item.title + td: a(href=`/api/play/${item.item_type}/${item.item_id}/${item.track_id}` hx-target="#player" hx-select="#player" hx-indicator="null" hx-push-url="false")= item.title td= item.artist td= item.item_title - let label = item.band_url.replace(/https?:\/\/(.*?)\.bandcamp\.com.*/, "$1") diff --git a/routes/app.js b/routes/app.js index 53e60dd..fb2caa3 100644 --- a/routes/app.js +++ b/routes/app.js @@ -25,12 +25,12 @@ const currencyExchange = new Map([ const sqls = { album_grid: "SELECT item.*, count(*) AS track_count, iif(sum(duration) > 3600, cast(total(duration)/3600 AS INTEGER) || 'h ' || cast(total(duration)/60%60 AS INTEGER) || 'm', cast(total(duration)/60 AS INTEGER) || 'm') AS total_duration FROM item INNER JOIN track USING (account, item_id) {JOIN TAG} WHERE account = ? {WHERE} GROUP BY item_id {ORDER}", album_list: "SELECT item.*, count(*) AS track_count, iif(sum(duration) > 3600, cast(total(duration)/3600 AS INTEGER) || 'h ' || cast(total(duration)/60%60 AS INTEGER) || 'm', cast(total(duration)/60 AS INTEGER) || 'm') AS total_duration FROM item INNER JOIN track USING (account, item_id) {JOIN TAG} WHERE account = ? {WHERE} GROUP BY item_id ORDER BY band_url, band_name COLLATE NOCASE, item_title COLLATE NOCASE", - artist_grid: "SELECT band_name, count(DISTINCT item_id) AS album_count, group_concat(DISTINCT band_url) AS labels, count(*) AS track_count, iif(sum(duration) > 3600, cast(total(duration)/3600 AS INTEGER) || 'h ' || cast(total(duration)/60%60 AS INTEGER) || 'm', cast(total(duration)/60 AS INTEGER) || 'm') AS total_duration FROM item INNER JOIN track USING (account, item_id) {JOIN TAG} WHERE account = ? {WHERE} GROUP BY band_name ORDER BY band_name COLLATE NOCASE", - artist_list: "SELECT band_name, count(DISTINCT item_id) AS album_count, band_url, count(*) AS track_count, iif(sum(duration) > 3600, cast(total(duration)/3600 AS INTEGER) || 'h ' || cast(total(duration)/60%60 AS INTEGER) || 'm', cast(total(duration)/60 AS INTEGER) || 'm') AS total_duration FROM item INNER JOIN track USING (account, item_id) {JOIN TAG} WHERE account = ? {WHERE} GROUP BY band_name ORDER BY band_name COLLATE NOCASE", - label_grid: "SELECT iif(count(DISTINCT band_name) = 1, band_name, band_url) AS display_name, band_url, count(DISTINCT item_id) AS album_count, count(DISTINCT band_name) AS artist_count, count(*) AS track_count, iif(sum(duration) > 3600, cast(total(duration)/3600 AS INTEGER) || 'h ' || cast(total(duration)/60%60 AS INTEGER) || 'm', cast(total(duration)/60 AS INTEGER) || 'm') AS total_duration FROM item INNER JOIN track USING (account, item_id) {JOIN TAG} WHERE account = ? {WHERE} GROUP BY band_url ORDER BY display_name COLLATE NOCASE", - label_list: "SELECT iif(count(DISTINCT band_name) = 1, band_name, band_url) AS display_name, band_url, count(DISTINCT item_id) AS album_count, count(DISTINCT band_name) AS artist_count, count(*) AS track_count, iif(sum(duration) > 3600, cast(total(duration)/3600 AS INTEGER) || 'h ' || cast(total(duration)/60%60 AS INTEGER) || 'm', cast(total(duration)/60 AS INTEGER) || 'm') AS total_duration FROM item INNER JOIN track USING (account, item_id) {JOIN TAG} WHERE account = ? {WHERE} GROUP BY band_url ORDER BY display_name COLLATE NOCASE", + artist_grid: "SELECT band_name, item_title, count(DISTINCT item_id) AS album_count, group_concat(DISTINCT band_url) AS labels, count(*) AS track_count, iif(sum(duration) > 3600, cast(total(duration)/3600 AS INTEGER) || 'h ' || cast(total(duration)/60%60 AS INTEGER) || 'm', cast(total(duration)/60 AS INTEGER) || 'm') AS total_duration FROM item INNER JOIN track USING (account, item_id) {JOIN TAG} WHERE account = ? {WHERE} GROUP BY band_name ORDER BY band_name COLLATE NOCASE", + artist_list: "SELECT band_name, item_title, count(DISTINCT item_id) AS album_count, band_url, count(*) AS track_count, iif(sum(duration) > 3600, cast(total(duration)/3600 AS INTEGER) || 'h ' || cast(total(duration)/60%60 AS INTEGER) || 'm', cast(total(duration)/60 AS INTEGER) || 'm') AS total_duration FROM item INNER JOIN track USING (account, item_id) {JOIN TAG} WHERE account = ? {WHERE} GROUP BY band_name ORDER BY band_name COLLATE NOCASE", + label_grid: "SELECT item_title, iif(count(DISTINCT band_name) = 1, band_name, band_url) AS display_name, band_url, count(DISTINCT item_id) AS album_count, count(DISTINCT band_name) AS artist_count, count(*) AS track_count, iif(sum(duration) > 3600, cast(total(duration)/3600 AS INTEGER) || 'h ' || cast(total(duration)/60%60 AS INTEGER) || 'm', cast(total(duration)/60 AS INTEGER) || 'm') AS total_duration FROM item INNER JOIN track USING (account, item_id) {JOIN TAG} WHERE account = ? {WHERE} GROUP BY band_url ORDER BY display_name COLLATE NOCASE", + label_list: "SELECT item_title, iif(count(DISTINCT band_name) = 1, band_name, band_url) AS display_name, band_url, count(DISTINCT item_id) AS album_count, count(DISTINCT band_name) AS artist_count, count(*) AS track_count, iif(sum(duration) > 3600, cast(total(duration)/3600 AS INTEGER) || 'h ' || cast(total(duration)/60%60 AS INTEGER) || 'm', cast(total(duration)/60 AS INTEGER) || 'm') AS total_duration FROM item INNER JOIN track USING (account, item_id) {JOIN TAG} WHERE account = ? {WHERE} GROUP BY band_url ORDER BY display_name COLLATE NOCASE", tag_grid: "SELECT tag, count(*) AS count FROM item_tag INNER JOIN item USING (account, item_id) WHERE account = ? {WHERE} GROUP BY tag, band_url ORDER BY count DESC", - tag_list: "SELECT tag, count(*) AS labels, sum(count) AS albums FROM (SELECT tag, count(*) AS count FROM item_tag INNER JOIN item USING (account, item_id) WHERE account = ? {WHERE} GROUP BY tag, band_url) GROUP BY tag ORDER BY labels DESC", + tag_list: "SELECT item_title, tag, count(*) AS labels, sum(count) AS albums FROM (SELECT item_title, tag, count(*) AS count FROM item_tag INNER JOIN item USING (account, item_id) WHERE account = ? {WHERE} GROUP BY tag, band_url) GROUP BY tag ORDER BY labels DESC", track_list: "SELECT * FROM track INNER JOIN item USING (account, item_id) {JOIN TAG} WHERE account = ? {WHERE} ORDER BY band_url, item_title COLLATE NOCASE, track_number" } diff --git a/routes/play.js b/routes/play.js index e70d6a4..d6414e3 100644 --- a/routes/play.js +++ b/routes/play.js @@ -10,10 +10,11 @@ const pugSync = sync.require("../pug-sync") const schema = z.object({ item_type: z.enum(["album", "track"]), - item_id: z.number({coerce: true}) + item_id: z.number({coerce: true}), + track_id: z.number({coerce: true}).optional() }) -router.get("/api/play/:item_type/:item_id", defineEventHandler(async event => { +router.get("/api/play/:item_type/:item_id/:track_id", defineEventHandler(async event => { const locals = await getValidatedRouterParams(event, schema.parse) return pugSync.render(event, "player.pug", locals) }))