Experiment to rebuild Diffuse using web applets.
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: artworker controller label

+94 -21
+50 -8
src/pages/constituents/blur/artwork-controller/_applet.astro
··· 50 50 51 51 .artwork { 52 52 flex: 1; 53 - pointer-events: none; 54 53 position: relative; 55 54 } 56 55 ··· 58 57 height: 100%; 59 58 left: 0; 60 59 object-fit: cover; 60 + pointer-events: none; 61 61 position: absolute; 62 62 top: 0; 63 63 width: 100%; 64 + z-index: 0; 65 + } 66 + 67 + .artwork label { 68 + background: oklch(0 0 0); 69 + border-radius: var(--radius-sm); 70 + box-shadow: var(--box-shadow-lg); 71 + font-size: var(--fs-2xs); 72 + font-weight: 600; 73 + left: var(--space-xs); 74 + letter-spacing: var(--tracking-wide); 75 + line-height: 1; 76 + padding: 7px 6px 6px; 77 + position: absolute; 78 + text-transform: uppercase; 79 + top: var(--space-xs); 80 + transition: 81 + background-color 500ms, 82 + color 500ms; 83 + z-index: 1; 64 84 } 65 85 66 86 /* Progress bars */ ··· 113 133 display: block; 114 134 font-style: normal; 115 135 line-height: var(--leading-snug); 116 - text-shadow: 117 - 0px 1px 0px rgba(0, 0, 0, 0.08), 118 - 0px 1px 1px rgba(0, 0, 0, 0.08), 119 - 0px 2px 2px rgba(0, 0, 0, 0.08); 136 + text-shadow: var(--text-shadow-sm); 120 137 } 121 138 122 139 /* Progress */ ··· 134 151 justify-content: space-between; 135 152 margin-top: var(--space-3xs); 136 153 opacity: 0.4; 137 - text-shadow: 0px 1px 1px rgb(0 0 0 / 0.2); 154 + text-shadow: var(--text-shadow-xs); 138 155 } 139 156 140 157 /* Controls */ ··· 314 331 // Signals 315 332 const [activeTrack, setActiveTrack] = signal<Track | undefined>(undefined); 316 333 const [artwork, setArtwork] = signal<Artwork[]>([]); 334 + const [artworkColor, setArtworkColor] = signal<string | undefined>(undefined); 317 335 const [duration, setDuration] = signal<string>("0:00"); 318 336 const [groupId, setGroupId] = signal<string | undefined>(context.groupId); 319 337 const [isPlaying, setIsPlaying] = signal<boolean>(false); ··· 474 492 475 493 // Remove existing artwork 476 494 // TODO: Fade in new artwork and then remove other 477 - showcase.innerHTML = ""; 495 + showcase.querySelectorAll("img").forEach((node) => { 496 + showcase.removeChild(node); 497 + }); 478 498 479 499 // Create img for new artwork 480 500 const img = h("img", { src: url, className: "artwork" }); ··· 483 503 img.onload = () => { 484 504 const fac = new FastAverageColor(); 485 505 const color = fac.getColor(img as HTMLImageElement); 506 + setArtworkColor(color.rgba); 507 + bg.style.backgroundColor = color.rgba; 486 508 main.style.backgroundColor = color.rgba; 487 - bg.style.backgroundColor = color.rgba; 488 509 }; 489 510 490 511 // Insert new artwork 491 512 showcase.appendChild(img); 492 513 }); 514 + 515 + //////////////////////////////////////////// 516 + // UI ░ GROUP ID 517 + //////////////////////////////////////////// 518 + 519 + const GroupId = h( 520 + "label", 521 + computed(() => { 522 + const gid = groupId(); 523 + const display = gid === undefined || gid.toLowerCase() === "main" ? "none" : "block"; 524 + 525 + return { 526 + attrs: { 527 + style: `background: ${artworkColor()}; display: ${display};`, 528 + }, 529 + }; 530 + }), 531 + text(context.groupId), 532 + ); 533 + 534 + showcase.appendChild(GroupId); 493 535 494 536 //////////////////////////////////////////// 495 537 // UI ░ NOW PLAYING
+1 -4
src/pages/themes/blur/index.astro
··· 5 5 <Page title="Diffuse"> 6 6 <script src="../../../scripts/themes/blur/index.js"></script> 7 7 8 - <main> 9 - <iframe src="../../constituents/blur/artwork-controller/?groupId=deck-a"></iframe> 10 - <iframe src="../../constituents/blur/artwork-controller/?groupId=deck-b"></iframe> 11 - </main> 8 + <main></main> 12 9 </Page>
+23 -8
src/scripts/themes/blur/index.ts
··· 1 1 import type { Applet } from "@web-applets/sdk"; 2 2 3 3 import type { ManagedOutput } from "@applets/core/types"; 4 - import { applet } from "@scripts/applets/common"; 4 + import { applet, reactive, wait } from "@scripts/applets/common"; 5 5 6 6 //////////////////////////////////////////// 7 7 // 🎨 Styles ··· 13 13 //////////////////////////////////////////// 14 14 import type * as QueueEngine from "@applets/engine/queue/types.d.ts"; 15 15 16 - const idA = "deck-a"; 17 - const idB = "deck-b"; 16 + const container = document.querySelector("main"); 17 + if (!container) throw new Error("Missing container"); 18 + 19 + const labelA = "Deck A"; 20 + const labelB = "Deck B"; 18 21 19 22 const configurator = { 20 23 output: await applet<ManagedOutput>("../../configurator/output"), 21 24 }; 22 25 26 + const constituents = { 27 + a: applet("../../constituents/blur/artwork-controller", { container, groupId: labelA }), 28 + b: applet("../../constituents/blur/artwork-controller", { container, groupId: labelB }), 29 + }; 30 + 23 31 const engine = { 24 32 queue: { 25 - A: await applet<QueueEngine.State>("../../engine/queue", { groupId: idA }), 26 - B: await applet<QueueEngine.State>("../../engine/queue", { groupId: idB }), 33 + a: await applet<QueueEngine.State>("../../engine/queue", { groupId: labelA }), 34 + b: await applet<QueueEngine.State>("../../engine/queue", { groupId: labelB }), 27 35 }, 28 36 }; 37 + 38 + const deckA = engine.queue.a; 39 + const deckB = engine.queue.b; 29 40 30 41 // TODO: Shuffle, limit track amount, etc. 31 42 async function fill(deck: Applet<QueueEngine.State>) { ··· 44 55 // Add tracks to the queue once the tracks have been loaded; 45 56 // and every time the collection changes. 46 57 47 - // wait(configurator.output, (d) => d?.tracks.state === "loaded").then(() => { 48 - // connect(configurator.output, (data) => data.tracks.cacheId, fill); 49 - // }); 58 + wait(configurator.output, (d) => d?.tracks.state === "loaded").then(() => { 59 + reactive( 60 + configurator.output, 61 + (data) => data.tracks.cacheId, 62 + () => fill(deckA), 63 + ); 64 + });
+2 -1
src/styles/themes/blur/index.css
··· 72 72 iframe[src*="/artwork-controller/"] { 73 73 grid-column: 3; 74 74 height: 100%; 75 - max-width: var(--container-2xs); 75 + justify-self: end; 76 + max-width: var(--container-3xs); 76 77 width: 100%; 77 78 }
+18
src/styles/variables.css
··· 61 61 --leading-normal: 1.5; 62 62 --leading-relaxed: 1.625; 63 63 --leading-loose: 2; 64 + 65 + /* Shadows */ 66 + --box-shadow-2xs: 0 1px rgb(0 0 0 / 0.05); 67 + --box-shadow-xs: 0 1px 2px 0 rgb(0 0 0 / 0.05); 68 + --box-shadow-sm: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); 69 + --box-shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); 70 + --box-shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); 71 + --box-shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1); 72 + --box-shadow-2xl: 0 25px 50px -12px rgb(0 0 0 / 0.25); 73 + 74 + --text-shadow-2xs: 0px 1px 0px rgb(0 0 0 / 0.15); 75 + --text-shadow-xs: 0px 1px 1px rgb(0 0 0 / 0.2); 76 + --text-shadow-sm: 77 + 0px 1px 0px rgb(0 0 0 / 0.075), 0px 1px 1px rgb(0 0 0 / 0.075), 0px 2px 2px rgb(0 0 0 / 0.075); 78 + --text-shadow-md: 79 + 0px 1px 1px rgb(0 0 0 / 0.1), 0px 1px 2px rgb(0 0 0 / 0.1), 0px 2px 4px rgb(0 0 0 / 0.1); 80 + --text-shadow-lg: 81 + 0px 1px 2px rgb(0 0 0 / 0.1), 0px 3px 2px rgb(0 0 0 / 0.1), 0px 4px 8px rgb(0 0 0 / 0.1); 64 82 }