Add settings for currency and inline player
This commit is contained in:
		
							parent
							
								
									6cc0003120
								
							
						
					
					
						commit
						82234f9706
					
				
					 10 changed files with 104 additions and 15 deletions
				
			
		| 
						 | 
					@ -9,3 +9,11 @@ function movePlayer() {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
movePlayer()
 | 
					movePlayer()
 | 
				
			||||||
document.body.addEventListener("htmx:load", movePlayer)
 | 
					document.body.addEventListener("htmx:load", movePlayer)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					document.querySelectorAll("[popovertarget]").forEach(e => {
 | 
				
			||||||
 | 
						e.addEventListener("click", () => {
 | 
				
			||||||
 | 
							const rect = e.getBoundingClientRect()
 | 
				
			||||||
 | 
							const t = `:popover-open { position: fixed; top: ${Math.floor(rect.bottom)}px; left: ${Math.floor(rect.left + rect.width / 2)}px; width: ${Math.floor(rect.width + 85)}px; transform: translateX(-50%); margin: 0 }`
 | 
				
			||||||
 | 
							document.styleSheets[0].insertRule(t, document.styleSheets[0].cssRules.length)
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -45,6 +45,9 @@ svg {
 | 
				
			||||||
button.s-link.is-loading {
 | 
					button.s-link.is-loading {
 | 
				
			||||||
	padding-left: 2.2em;
 | 
						padding-left: 2.2em;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					.s-btn__dropdown:has(+ :popover-open) {
 | 
				
			||||||
 | 
						background-color: var(--theme-topbar-item-background-hover, var(--black-200)) !important;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* album covers are done with styles instead of attributes to reduce bytes of html needing to be downloaded and parsed */
 | 
					/* album covers are done with styles instead of attributes to reduce bytes of html needing to be downloaded and parsed */
 | 
				
			||||||
.cover {
 | 
					.cover {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,7 +9,7 @@ block view
 | 
				
			||||||
    .d-grid.gx8.gy12.jc-center.break-word(style="grid-template-columns: repeat(auto-fit, 210px)")
 | 
					    .d-grid.gx8.gy12.jc-center.break-word(style="grid-template-columns: repeat(auto-fit, 210px)")
 | 
				
			||||||
      each item in items
 | 
					      each item in items
 | 
				
			||||||
        div
 | 
					        div
 | 
				
			||||||
          a.cover(href=item.item_url hx-get=`/api/play/${item.item_type}/${item.item_id}` hx-target="#player" hx-select="#player" hx-indicator="null" hx-push-url="false")
 | 
					          a.cover&attributes(getAlbumCoverAttributes(event, item))
 | 
				
			||||||
            picture
 | 
					            picture
 | 
				
			||||||
              img(loading="lazy" src=item.item_art_url width=210 height=210)
 | 
					              img(loading="lazy" src=item.item_art_url width=210 height=210)
 | 
				
			||||||
              != icons.use("play-solid", 64)
 | 
					              != icons.use("play-solid", 64)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,5 +28,5 @@ block view
 | 
				
			||||||
                  span.s-tag--sponsor!= icons.use("flower", 16)
 | 
					                  span.s-tag--sponsor!= icons.use("flower", 16)
 | 
				
			||||||
                  = label
 | 
					                  = label
 | 
				
			||||||
          each preview in item.previews
 | 
					          each preview in item.previews
 | 
				
			||||||
            a.d-flex(href=preview.item_url hx-get=`/api/play/${preview.item_type}/${preview.item_id}` hx-target="#player" hx-select="#player" hx-indicator="null" hx-push-url="false")
 | 
					            a.d-flex&attributes(getAlbumCoverAttributes(event, preview))
 | 
				
			||||||
              img(loading="lazy" src=preview.item_art_url width=210 height=210 style="height: auto; width: auto; max-height: 70px")
 | 
					              img(loading="lazy" src=preview.item_art_url width=210 height=210 style="height: auto; width: auto; max-height: 70px")
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,7 +13,7 @@ html
 | 
				
			||||||
      .s-topbar--container.wmx9
 | 
					      .s-topbar--container.wmx9
 | 
				
			||||||
          .s-topbar--logo
 | 
					          .s-topbar--logo
 | 
				
			||||||
            != icons.get("compass-solid", 24)
 | 
					            != icons.get("compass-solid", 24)
 | 
				
			||||||
            .ml4 BC Explorer
 | 
					            .ml6 BC Explorer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .mx-auto.wmx9.py24.px16.g24
 | 
					    .mx-auto.wmx9.py24.px16.g24
 | 
				
			||||||
      .s-prose
 | 
					      .s-prose
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -29,9 +29,36 @@ html
 | 
				
			||||||
    #page(hx-history-elt)
 | 
					    #page(hx-history-elt)
 | 
				
			||||||
      header.s-topbar.ps-sticky.t0
 | 
					      header.s-topbar.ps-sticky.t0
 | 
				
			||||||
        .s-topbar--container.wmx9
 | 
					        .s-topbar--container.wmx9
 | 
				
			||||||
          .s-topbar--logo
 | 
					          button.s-topbar--logo.s-btn.s-btn__muted.s-btn__dropdown.pr24.bar0.fc-black(popovertarget="menu")
 | 
				
			||||||
            != icons.get("compass-solid", 24)
 | 
					            != icons.get("compass-solid", 24)
 | 
				
			||||||
            .ml4 BC Explorer
 | 
					            .ml6 BC Explorer
 | 
				
			||||||
 | 
					          #menu(popover data-popper-placement="bottom" style="display: revert;").s-popover.overflow-visible.px0.py8
 | 
				
			||||||
 | 
					            .s-popover--arrow.s-popover--arrow__tc
 | 
				
			||||||
 | 
					            ul.s-menu(role="menu")
 | 
				
			||||||
 | 
					              li(role="menuitem")
 | 
				
			||||||
 | 
					                a.s-block-link.d-flex.ai-center.fc-black(href="/" hx-boost="false")
 | 
				
			||||||
 | 
					                  != icons.get("log-out")
 | 
				
			||||||
 | 
					                  .ml6 Switch account
 | 
				
			||||||
 | 
					              li.s-menu--divider(role="separator")
 | 
				
			||||||
 | 
					              li.s-menu--title Settings
 | 
				
			||||||
 | 
					              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
 | 
				
			||||||
 | 
					                    != icons.get("layout-right")
 | 
				
			||||||
 | 
					                    .pl6(for="inline-player-switch") Inline player
 | 
				
			||||||
 | 
					                  #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")
 | 
				
			||||||
 | 
					                  label.fl-grow1(for="currency-select").d-flex.ai-center
 | 
				
			||||||
 | 
					                    != icons.get("coins")
 | 
				
			||||||
 | 
					                    .pl6 Currency
 | 
				
			||||||
 | 
					                  #currency-loading
 | 
				
			||||||
 | 
					                  input(type="hidden" name="account" value=account)
 | 
				
			||||||
 | 
					                  .s-select
 | 
				
			||||||
 | 
					                    select#currency-select(name="currency")
 | 
				
			||||||
 | 
					                      each currency in currencies
 | 
				
			||||||
 | 
					                        option(selected=(currency === count.displayCurrency))= currency
 | 
				
			||||||
          .fl-grow1
 | 
					          .fl-grow1
 | 
				
			||||||
          nav
 | 
					          nav
 | 
				
			||||||
            ul.s-navigation
 | 
					            ul.s-navigation
 | 
				
			||||||
| 
						 | 
					@ -79,7 +106,7 @@ html
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            #collection-sync.d-none
 | 
					            #collection-sync.d-none
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            .s-sidebarwidget
 | 
					            #collection-stats.s-sidebarwidget
 | 
				
			||||||
              .s-sidebarwidget--header Collection
 | 
					              .s-sidebarwidget--header Collection
 | 
				
			||||||
                .s-sidebarwidget--action
 | 
					                .s-sidebarwidget--action
 | 
				
			||||||
                  input(type="hidden" name="account" value=account)
 | 
					                  input(type="hidden" name="account" value=account)
 | 
				
			||||||
| 
						 | 
					@ -125,7 +152,7 @@ html
 | 
				
			||||||
                tr.s-sidebarwidget--item
 | 
					                tr.s-sidebarwidget--item
 | 
				
			||||||
                  th value
 | 
					                  th value
 | 
				
			||||||
                  td
 | 
					                  td
 | 
				
			||||||
                    = `${count.displayCurrencySymbol}${count.value} `
 | 
					                    = `${count.value} `
 | 
				
			||||||
                    span.fc-black-400 #{count.displayCurrency}
 | 
					                    span.fc-black-400 #{count.displayCurrency}
 | 
				
			||||||
                tr.s-sidebarwidget--item
 | 
					                tr.s-sidebarwidget--item
 | 
				
			||||||
                  th diversity
 | 
					                  th diversity
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,5 +28,5 @@ block view
 | 
				
			||||||
                  span.s-tag--sponsor!= icons.use("compact-disc", 16)
 | 
					                  span.s-tag--sponsor!= icons.use("compact-disc", 16)
 | 
				
			||||||
                  = item.total_duration
 | 
					                  = item.total_duration
 | 
				
			||||||
          each preview in item.previews
 | 
					          each preview in item.previews
 | 
				
			||||||
            a.d-flex(href=preview.item_url hx-get=`/api/play/${preview.item_type}/${preview.item_id}` hx-target="#player" hx-select="#player" hx-indicator="null" hx-push-url="false")
 | 
					            a.d-flex&attributes(getAlbumCoverAttributes(event, preview))
 | 
				
			||||||
              img(loading="lazy" src=preview.item_art_url width=210 height=210 style="height: auto; width: auto; max-height: 70px")
 | 
					              img(loading="lazy" src=preview.item_art_url width=210 height=210 style="height: auto; width: auto; max-height: 70px")
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,17 +1,16 @@
 | 
				
			||||||
// @ts-check
 | 
					// @ts-check
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const {z} = require("zod")
 | 
					const {z} = require("zod")
 | 
				
			||||||
const {defineEventHandler, getQuery, getValidatedQuery, sendRedirect, createError, getValidatedRouterParams} = require("h3")
 | 
					const {defineEventHandler, getQuery, getValidatedQuery, sendRedirect, createError, getValidatedRouterParams, getCookie} = require("h3")
 | 
				
			||||||
const {router, db, sync, select, from} = require("../passthrough")
 | 
					const {router, db, sync, select, from} = require("../passthrough")
 | 
				
			||||||
const pugSync = sync.require("../pug-sync")
 | 
					const pugSync = sync.require("../pug-sync")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** @type {import("./load-tags")} */
 | 
					/** @type {import("./load-tags")} */
 | 
				
			||||||
const loadTags = sync.require("./load-tags")
 | 
					const loadTags = sync.require("./load-tags")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const displayCurrency = "NZD"
 | 
					 | 
				
			||||||
const displayCurrencySymbol = "$"
 | 
					 | 
				
			||||||
const currencyExchange = new Map([
 | 
					const currencyExchange = new Map([
 | 
				
			||||||
	["AUD", 0.63],
 | 
						["AUD", 0.63],
 | 
				
			||||||
 | 
						["BRL", 0.17],
 | 
				
			||||||
	["CAD", 0.7],
 | 
						["CAD", 0.7],
 | 
				
			||||||
	["CHF", 1.13],
 | 
						["CHF", 1.13],
 | 
				
			||||||
	["EUR", 1.08],
 | 
						["EUR", 1.08],
 | 
				
			||||||
| 
						 | 
					@ -63,6 +62,24 @@ function loadPreviews(locals, field, number, whereClause, account, filter_field,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pugSync.addGlobals({
 | 
				
			||||||
 | 
						getAlbumCoverAttributes(event, item) {
 | 
				
			||||||
 | 
							/** @type {any} */
 | 
				
			||||||
 | 
							let attributes = {
 | 
				
			||||||
 | 
								"hx-get": `/api/play/${item.item_type}/${item.item_id}`,
 | 
				
			||||||
 | 
								"hx-target": "#player",
 | 
				
			||||||
 | 
								"hx-select": "#player",
 | 
				
			||||||
 | 
								"hx-indicator": "null",
 | 
				
			||||||
 | 
								"hx-push-url": "false"
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (getCookie(event, "bcex-inline-player-disabled") === "true") {
 | 
				
			||||||
 | 
								attributes = {"target": "_blank"}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							attributes.href = item.item_url
 | 
				
			||||||
 | 
							return attributes
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const schema = {
 | 
					const schema = {
 | 
				
			||||||
	query: z.object({
 | 
						query: z.object({
 | 
				
			||||||
		arrange: z.enum(["album", "artist", "label", "tag", "track"]),
 | 
							arrange: z.enum(["album", "artist", "label", "tag", "track"]),
 | 
				
			||||||
| 
						 | 
					@ -132,6 +149,11 @@ router.get("/:account/", defineEventHandler({
 | 
				
			||||||
			console.error(sql, params)
 | 
								console.error(sql, params)
 | 
				
			||||||
			throw e
 | 
								throw e
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							let displayCurrency = getCookie(event, "bcex-currency") || ""
 | 
				
			||||||
 | 
							if (!currencyExchange.has(displayCurrency)) displayCurrency = "NZD"
 | 
				
			||||||
 | 
							const currencyRoundTo = displayCurrency === "JPY" ? 1000 : 10
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		const locals = {
 | 
							const locals = {
 | 
				
			||||||
			items,
 | 
								items,
 | 
				
			||||||
			account,
 | 
								account,
 | 
				
			||||||
| 
						 | 
					@ -149,12 +171,12 @@ router.get("/:account/", defineEventHandler({
 | 
				
			||||||
				avgTags: Math.round(db.prepare("SELECT avg(count) FROM (SELECT count(*) AS count FROM item_tag WHERE account = ? GROUP BY item_id)").pluck().get(account)*10)/10,
 | 
									avgTags: Math.round(db.prepare("SELECT avg(count) FROM (SELECT count(*) AS count FROM item_tag WHERE account = ? GROUP BY item_id)").pluck().get(account)*10)/10,
 | 
				
			||||||
				lonelyTags: db.prepare("SELECT count(*) FROM (SELECT tag FROM item_tag WHERE account = ? GROUP BY tag HAVING count(*) = 1)").pluck().get(account),
 | 
									lonelyTags: db.prepare("SELECT count(*) FROM (SELECT tag FROM item_tag WHERE account = ? GROUP BY tag HAVING count(*) = 1)").pluck().get(account),
 | 
				
			||||||
				value: Math.round(select("item", ["currency", "price"], {account}).all().map(c => {
 | 
									value: Math.round(select("item", ["currency", "price"], {account}).all().map(c => {
 | 
				
			||||||
					return (currencyExchange.get(c.currency) || 0.6) * c.price / (currencyExchange.get(displayCurrency) || 1) / 10
 | 
										return (currencyExchange.get(c.currency) || 0.6) * c.price / (currencyExchange.get(displayCurrency) || 1) / currencyRoundTo
 | 
				
			||||||
				}).reduce((a, c) => a + c, 0)) * 10,
 | 
									}).reduce((a, c) => a + c, 0)) * currencyRoundTo,
 | 
				
			||||||
				displayCurrency,
 | 
									displayCurrency,
 | 
				
			||||||
				displayCurrencySymbol,
 | 
					 | 
				
			||||||
				taste: db.prepare("with popularity (a) as (select avg(also_collected_count) from item WHERE account = ? group by band_url) select sum(iif(a >= 0 and a < 20, 1, 0)) as cold, sum(iif(a >= 20 and a < 200, 1, 0)) as warm, sum(iif(a >= 200 and a < 2000, 1, 0)) as hot, sum(iif(a >= 2000, 1, 0)) as supernova from popularity").raw().get(account)
 | 
									taste: db.prepare("with popularity (a) as (select avg(also_collected_count) from item WHERE account = ? group by band_url) select sum(iif(a >= 0 and a < 20, 1, 0)) as cold, sum(iif(a >= 20 and a < 200, 1, 0)) as warm, sum(iif(a >= 200 and a < 2000, 1, 0)) as hot, sum(iif(a >= 2000, 1, 0)) as supernova from popularity").raw().get(account)
 | 
				
			||||||
			}
 | 
								},
 | 
				
			||||||
 | 
								currencies: [...currencyExchange.keys()]
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (mode === "artist_grid") {
 | 
							if (mode === "artist_grid") {
 | 
				
			||||||
			loadPreviews(locals, "band_name", 4, whereClause, account, filter_field, filter, filter_fuzzy)
 | 
								loadPreviews(locals, "band_name", 4, whereClause, account, filter_field, filter, filter_fuzzy)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										28
									
								
								routes/settings.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								routes/settings.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,28 @@
 | 
				
			||||||
 | 
					// @ts-check
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const {z} = require("zod")
 | 
				
			||||||
 | 
					const {router} = require("../passthrough")
 | 
				
			||||||
 | 
					const {defineEventHandler, readValidatedBody, setCookie, setResponseHeader, sendRedirect} = require("h3")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const schema = {
 | 
				
			||||||
 | 
						inline_player: z.object({
 | 
				
			||||||
 | 
							inline_player: z.string().optional()
 | 
				
			||||||
 | 
						}),
 | 
				
			||||||
 | 
						currency: z.object({
 | 
				
			||||||
 | 
							currency: z.string().regex(/^[A-Z]{3}$/),
 | 
				
			||||||
 | 
							account: z.string()
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					router.post("/api/settings/inline-player", defineEventHandler(async event => {
 | 
				
			||||||
 | 
						const {inline_player} = await readValidatedBody(event, schema.inline_player.parse)
 | 
				
			||||||
 | 
						setCookie(event, "bcex-inline-player-disabled", String(!inline_player))
 | 
				
			||||||
 | 
						setResponseHeader(event, "HX-Refresh", "true")
 | 
				
			||||||
 | 
						return null
 | 
				
			||||||
 | 
					}))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					router.post("/api/settings/currency", defineEventHandler(async event => {
 | 
				
			||||||
 | 
						const {currency, account} = await readValidatedBody(event, schema.currency.parse)
 | 
				
			||||||
 | 
						setCookie(event, "bcex-currency", currency)
 | 
				
			||||||
 | 
						return sendRedirect(event, `/${account}/?arrange=tag&shape=grid`, 302)
 | 
				
			||||||
 | 
					}))
 | 
				
			||||||
							
								
								
									
										1
									
								
								start.js
									
										
									
									
									
								
							
							
						
						
									
										1
									
								
								start.js
									
										
									
									
									
								
							| 
						 | 
					@ -37,6 +37,7 @@ pugSync.createRoute(router, "/", "home.pug")
 | 
				
			||||||
sync.require("./routes/app")
 | 
					sync.require("./routes/app")
 | 
				
			||||||
sync.require("./routes/load-collection")
 | 
					sync.require("./routes/load-collection")
 | 
				
			||||||
sync.require("./routes/play")
 | 
					sync.require("./routes/play")
 | 
				
			||||||
 | 
					sync.require("./routes/settings")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Files
 | 
					// Files
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue