From a070fb6cdd3c31b9c66c896c1e0f164e802ca101 Mon Sep 17 00:00:00 2001 From: Steven Vandevelde Date: Tue, 2 Jun 2026 14:14:18 +0200 Subject: [PATCH] feat(themes/winamp): track details --- src/facets/data/process-tracks/index.html | 1 + src/facets/themes/winamp/98-scrollbar.css | 7 + src/facets/themes/winamp/browser/element.js | 8 +- .../themes/winamp/browser/facet/index.html | 1 + src/facets/themes/winamp/facet/index.html | 19 ++ .../themes/winamp/facet/index.inline.js | 1 + .../themes/winamp/track-details/element.js | 218 ++++++++++++++++++ src/facets/themes/winamp/window/element.js | 1 + 8 files changed, 249 insertions(+), 7 deletions(-) create mode 100644 src/facets/themes/winamp/98-scrollbar.css create mode 100644 src/facets/themes/winamp/track-details/element.js diff --git a/src/facets/data/process-tracks/index.html b/src/facets/data/process-tracks/index.html index 51221705..ed5cd40b 100644 --- a/src/facets/data/process-tracks/index.html +++ b/src/facets/data/process-tracks/index.html @@ -21,6 +21,7 @@ @import "./facets/themes/winamp/facet.css"; @import "./vendor/98.css"; + @import "./facets/themes/winamp/98-scrollbar.css"; @import "./facets/themes/winamp/98-vars.css"; @import "./facets/themes/winamp/98-extra.css"; diff --git a/src/facets/themes/winamp/98-scrollbar.css b/src/facets/themes/winamp/98-scrollbar.css new file mode 100644 index 00000000..eff12984 --- /dev/null +++ b/src/facets/themes/winamp/98-scrollbar.css @@ -0,0 +1,7 @@ +/* 98.css enables all four scrollbar button slots, showing two at each end. Hide the redundant ones. */ +::-webkit-scrollbar-button:vertical:start:increment, +::-webkit-scrollbar-button:vertical:end:decrement, +::-webkit-scrollbar-button:horizontal:start:increment, +::-webkit-scrollbar-button:horizontal:end:decrement { + display: none; +} diff --git a/src/facets/themes/winamp/browser/element.js b/src/facets/themes/winamp/browser/element.js index 43973a9b..6629b3d8 100644 --- a/src/facets/themes/winamp/browser/element.js +++ b/src/facets/themes/winamp/browser/element.js @@ -645,17 +645,11 @@ class Browser extends DiffuseElement { return html` + diff --git a/src/facets/themes/winamp/facet/index.html b/src/facets/themes/winamp/facet/index.html index be85cfdd..adf0254b 100644 --- a/src/facets/themes/winamp/facet/index.html +++ b/src/facets/themes/winamp/facet/index.html @@ -97,6 +97,19 @@ > + + + + Track details + + + + Artwork + + + + + + diff --git a/src/facets/themes/winamp/facet/index.inline.js b/src/facets/themes/winamp/facet/index.inline.js index b3a35a31..a424d31c 100644 --- a/src/facets/themes/winamp/facet/index.inline.js +++ b/src/facets/themes/winamp/facet/index.inline.js @@ -26,6 +26,7 @@ await foundation.configurator.input(); await import("~/facets/themes/winamp/browser/element.js"); await import("~/facets/themes/winamp/window/element.js"); await import("~/facets/themes/winamp/artwork/element.js"); +await import("~/facets/themes/winamp/track-details/element.js"); const { default: WinampElement } = await import( "~/facets/themes/winamp/winamp/element.js" diff --git a/src/facets/themes/winamp/track-details/element.js b/src/facets/themes/winamp/track-details/element.js new file mode 100644 index 00000000..2b8ad970 --- /dev/null +++ b/src/facets/themes/winamp/track-details/element.js @@ -0,0 +1,218 @@ +import { + defineElement, + DiffuseElement, + query, + whenElementsDefined, +} from "~/common/element.js"; +import { signal } from "~/common/signal.js"; + +/** + * @import {RenderArg} from "~/common/element.d.ts" + * + * @import ControllerOrchestrator from "~/components/orchestrator/controller/element.js" + * @import FavouritesOrchestrator from "~/components/orchestrator/favourites/element.js" + */ + +class TrackDetailsElement extends DiffuseElement { + constructor() { + super(); + this.attachShadow({ mode: "open" }); + } + + // SIGNALS - DEPENDENCIES + + $controller = signal(/** @type {ControllerOrchestrator | undefined} */ (undefined)); + $favourites = signal(/** @type {FavouritesOrchestrator | undefined} */ (undefined)); + + // COMPUTED + + currentTrack = () => this.$controller.value?.currentTrack(); + + // LIFECYCLE + + /** + * @override + */ + connectedCallback() { + super.connectedCallback(); + + /** @type {ControllerOrchestrator} */ + const controller = query(this, "controller-orchestrator-selector"); + + /** @type {FavouritesOrchestrator} */ + const favourites = query(this, "favourites-orchestrator-selector"); + + whenElementsDefined({ controller, favourites }).then(() => { + this.$controller.value = controller; + this.$favourites.value = favourites; + }); + } + + // ACTIONS + + toggleFavourite = () => { + const track = this.currentTrack(); + if (track) this.$favourites.value?.toggle(track); + }; + + /** + * @param {RenderArg} _ + */ + render({ html }) { + const track = this.currentTrack(); + const isFav = track ? (this.$favourites.value?.isFavourite(track) ?? false) : false; + + const title = track?.tags?.title ?? "—"; + const artist = track?.tags?.artist ?? "—"; + const album = track?.tags?.album ?? "—"; + const year = track?.tags?.year ?? null; + + const durationMs = track?.stats?.duration ?? null; + const duration = durationMs != null ? formatDuration(durationMs) : "—"; + + const bitrate = track?.stats?.bitrate != null + ? `${Math.round(track.stats.bitrate / 1000)} kbps` + : "—"; + + const sampleRate = track?.stats?.sampleRate != null + ? `${Math.round(track.stats.sampleRate / 1000)} kHz` + : "—"; + + const codec = track?.stats?.codec ?? "—"; + const channels = track?.stats?.numberOfChannels ?? null; + + return html` + + + + + +
+ ${track + ? html` +
+ Track +
+ Title + ${title} +
+
+ Artist + ${artist} +
+
+ Album + ${album} +
+ ${year != null + ? html`
+ Year + ${year} +
` + : html``} +
+ +
+ Audio +
+ Duration + ${duration} +
+
+ Bitrate + ${bitrate} +
+
+ Sample rate + ${sampleRate} +
+
+ Codec + ${codec} +
+ ${channels != null + ? html`
+ Channels + ${channels} +
` + : html``} +
+ + + ` + : html`
No track playing
`} +
+ `; + } +} + +export default TrackDetailsElement; + +//////////////////////////////////////////// +// REGISTER +//////////////////////////////////////////// + +export const CLASS = TrackDetailsElement; +export const NAME = "dtw-winamp-track-details"; + +defineElement(NAME, TrackDetailsElement); + +/** + * @param {number} ms + * @returns {string} + */ +function formatDuration(ms) { + const totalSeconds = Math.floor(ms / 1000); + const minutes = Math.floor(totalSeconds / 60); + const seconds = totalSeconds % 60; + return `${minutes}:${seconds.toString().padStart(2, "0")}`; +} diff --git a/src/facets/themes/winamp/window/element.js b/src/facets/themes/winamp/window/element.js index 61143f9a..b21d1f12 100644 --- a/src/facets/themes/winamp/window/element.js +++ b/src/facets/themes/winamp/window/element.js @@ -36,6 +36,7 @@ class WindowElement extends DiffuseElement { render({ html }) { return html` +