From 62e7ccf17be664a440660e7a9d6178023406bc75 Mon Sep 17 00:00:00 2001 From: Cadence Ember Date: Thu, 10 Apr 2025 14:44:17 +1200 Subject: [PATCH] Filter location tags --- public/player-marker.js | 2 +- pug/includes/layout.pug | 24 ++++++++++- pug/tag_grid.pug | 93 ++++++++++++++++++++++------------------- routes/schema.js | 10 ++++- routes/settings.js | 11 ++++- 5 files changed, 93 insertions(+), 47 deletions(-) diff --git a/public/player-marker.js b/public/player-marker.js index 7c696f1..87f5635 100644 --- a/public/player-marker.js +++ b/public/player-marker.js @@ -22,7 +22,7 @@ function addPopoverStyle() { document.querySelectorAll("[popovertarget]").forEach(e => { e.addEventListener("click", () => { const rect = e.getBoundingClientRect() - const width = Math.floor(rect.width + 85) + const width = 266 const left = Math.max(Math.floor(rect.left + rect.width / 2), width / 2) const t = `:popover-open { position: fixed; top: ${Math.floor(rect.bottom)}px; left: ${left}px; width: ${width}px; transform: translateX(-50%); margin: 0 }` document.styleSheets[0].insertRule(t, document.styleSheets[0].cssRules.length) diff --git a/pug/includes/layout.pug b/pug/includes/layout.pug index 5b74e7d..5d2077b 100644 --- a/pug/includes/layout.pug +++ b/pug/includes/layout.pug @@ -44,6 +44,28 @@ html .ml6 Switch account li.s-menu--divider(role="separator") li.s-menu--title Settings + li(role="menuitem") + if arrange === "tag" + form.s-block-link.d-flex.ai-center(hx-post="/api/settings/location-tags" hx-trigger="change" hx-indicator="#location-tags-loading" hx-select="#tag-page" hx-target="#tag-page") + span.fl-grow1.d-flex.ai-center + != icons.get("map-pin") + .pl6 Region tags + #location-tags-loading + input(type="hidden" name="account" value=account) + .s-toggle-switch.s-toggle-switch__multiple + - const locationTagsSetting = h3.getCookie(event, "bcex-location-tags") || "all" + input#location-tags-all(type="radio" name="location_tags" value="all" autocomplete="off" checked=(locationTagsSetting === "all")) + label.px8.py6(for="location-tags-all") All + input#location-tags-hide(type="radio" name="location_tags" value="hide" autocomplete="off" checked=(locationTagsSetting === "hide")) + label.px8.py6(for="location-tags-hide") Hide + input#location-tags-only(type="radio" name="location_tags" value="only" autocomplete="off" checked=(locationTagsSetting === "only")) + label.px8.py6(for="location-tags-only") Only + else + .s-block-link.d-flex.ai-center + span.fl-grow1.d-flex.ai-center.fc-black-400 + != icons.get("map-pin") + .pl6 Region tags + a.fc-black-400.td-underline(href=and({arrange: "tag"})) Set on tags view li(role="menuitem") form.s-block-link.d-flex.ai-center(hx-post="/api/settings/inline-player" hx-trigger="change" hx-indicator="#inline-player-loading") label.fl-grow1.d-flex.ai-center @@ -52,7 +74,7 @@ html #inline-player-loading input.s-toggle-switch#inline-player-switch(type="checkbox" name="inline_player" checked=(h3.getCookie(event, "bcex-inline-player-disabled") !== "true")) li(role="menuitem") - form.s-block-link.d-flex.ai-center(hx-post="/api/settings/currency" hx-trigger="change" hx-select="#collection-stats" hx-target="#collection-stats" hx-indicator="#currency-loading") + form.s-block-link.py2.d-flex.ai-center(hx-post="/api/settings/currency" hx-trigger="change" hx-select="#collection-stats" hx-target="#collection-stats" hx-indicator="#currency-loading") label.fl-grow1(for="currency-select").d-flex.ai-center != icons.get("coins") .pl6 Currency diff --git a/pug/tag_grid.pug b/pug/tag_grid.pug index 88a4198..03bed83 100644 --- a/pug/tag_grid.pug +++ b/pug/tag_grid.pug @@ -4,47 +4,56 @@ block title - title = `Tags | ${title}` block view - script - | var items = - != JSON.stringify(items) - | ; var filter_field = - != JSON.stringify(filter_field || null) - .mx-auto.w100.wmx11.fs-body1 - .word-cloud(style="cursor: default") - script. - setTimeout(() => { - const content = document.querySelector(".word-cloud") - content.style.height = `${Math.round(Math.min(content.clientWidth, window.innerHeight)*0.8)}px` - const dark = window.matchMedia?.("(prefers-color-scheme: dark)").matches - WordCloud(content, { - list: items, - fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI Adjusted", "Segoe UI", "Liberation Sans", sans-serif', - fontWeight: "bold", - color: dark ? "random-light": "random-dark", - minSize: 4, - gridSize: Math.round(content.clientWidth / 200), - weightFactor: size => size * content.clientWidth / 180, - rotateRatio: 0, - click: item => { - const highlightedItem = document.querySelector(".wc-hl")?.textContent || item[0] - const newURL = new URL(location) - newURL.searchParams.set("filter", highlightedItem) - newURL.searchParams.set("filter_field", "tag") - newURL.searchParams.delete("filter_fuzzy") - newURL.searchParams.set("arrange", filter_field ? "album" : "label") - content.setAttribute("hx-push-url", newURL) // workaround for https://github.com/bigskysoftware/htmx/issues/2744 - htmx.ajax("GET", newURL.search, {context: content, source: content}) - } + #tag-page + script + - + const locationTags = location_tags || h3.getCookie(event, "bcex-location-tags") || "all" + const filteredItems = items.filter(item => { + if (locationTags === "all") return true + const isLocation = item[0][0].match(/[A-Z]/) + if (locationTags === "only") return isLocation + else return !isLocation }) - content.style.background = "none" - content.addEventListener("wordcloudstop", () => { - for (const child of content.children) { - child.addEventListener("mouseenter", () => { - child.classList.add("wc-hl") - }) - child.addEventListener("mouseleave", () => { - child.classList.remove("wc-hl") - }) - } + | var items = + != JSON.stringify(filteredItems) + | ; var filter_field = + != JSON.stringify(filter_field || null) + .mx-auto.w100.wmx11.fs-body1 + .word-cloud(style="cursor: default") + script. + setTimeout(() => { + const content = document.querySelector(".word-cloud") + content.style.height = `${Math.round(Math.min(content.clientWidth, window.innerHeight)*0.8)}px` + const dark = window.matchMedia?.("(prefers-color-scheme: dark)").matches + WordCloud(content, { + list: items, + fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI Adjusted", "Segoe UI", "Liberation Sans", sans-serif', + fontWeight: "bold", + color: dark ? "random-light": "random-dark", + minSize: 4, + gridSize: Math.round(content.clientWidth / 200), + weightFactor: size => size * content.clientWidth / 180, + rotateRatio: 0, + click: item => { + const highlightedItem = document.querySelector(".wc-hl")?.textContent || item[0] + const newURL = new URL(location) + newURL.searchParams.set("filter", highlightedItem) + newURL.searchParams.set("filter_field", "tag") + newURL.searchParams.delete("filter_fuzzy") + newURL.searchParams.set("arrange", filter_field ? "album" : "label") + content.setAttribute("hx-push-url", newURL) // workaround for https://github.com/bigskysoftware/htmx/issues/2744 + htmx.ajax("GET", newURL.search, {context: content, source: content}) + } + }) + content.style.background = "none" + content.addEventListener("wordcloudstop", () => { + for (const child of content.children) { + child.addEventListener("mouseenter", () => { + child.classList.add("wc-hl") + }) + child.addEventListener("mouseleave", () => { + child.classList.remove("wc-hl") + }) + } + }) }) - }) diff --git a/routes/schema.js b/routes/schema.js index 2b5a6b4..0037f5c 100644 --- a/routes/schema.js +++ b/routes/schema.js @@ -2,6 +2,8 @@ const {z} = require("zod") +const account = z.string().regex(/^[a-z0-9_-]+$/) + const schema = { appQuery: z.object({ arrange: z.enum(["album", "artist", "label", "tag", "track"]), @@ -11,11 +13,11 @@ const schema = { filter_fuzzy: z.enum(["true"]).optional() }), account: z.object({ - account: z.string().regex(/^[a-z0-9_-]+$/) + account }), postCurrency: z.object({ currency: z.string().regex(/^[A-Z]{3}$/), - account: z.string() + account }), play: z.object({ item_type: z.enum(["album", "track"]), @@ -24,6 +26,10 @@ const schema = { }), inlinePlayer: z.object({ inline_player: z.string().optional() + }), + locationTags: z.object({ + location_tags: z.enum(["all", "hide", "only"]), + account }) } diff --git a/routes/settings.js b/routes/settings.js index 207619e..c98babd 100644 --- a/routes/settings.js +++ b/routes/settings.js @@ -1,7 +1,10 @@ // @ts-check const {sync, router} = require("../passthrough") -const {defineEventHandler, readValidatedBody, setCookie, setResponseHeader} = require("h3") +const {defineEventHandler, readValidatedBody, setCookie, setResponseHeader, sendRedirect} = require("h3") + +/** @type {import("../pug-sync")} */ +const pugSync = sync.require("../pug-sync") /** @type {import("./schema")} */ const schema = sync.require("./schema") @@ -12,3 +15,9 @@ router.post("/api/settings/inline-player", defineEventHandler(async event => { setResponseHeader(event, "HX-Refresh", "true") return null })) + +router.post("/api/settings/location-tags", defineEventHandler(async event => { + const {location_tags, account} = await readValidatedBody(event, schema.schema.locationTags.parse) + setCookie(event, "bcex-location-tags", location_tags) + return sendRedirect(event, `/${account}/?arrange=tag&shape=grid`) +}))