mini player + dark glass: eight shapes run by the hidden main as the one brain, dissolving covers and accents, drag from anywhere, and the space between the panes turned to real acrylic - with the webview flags that keep rest frames honest

This commit is contained in:
KeelrLeek committed 2026-08-26 07:56:00 -05:00
1 parent 9b84b30aef
commit dc7ea16b22
33 files changed
+2432 -5

No files matched your search

+119
View File
@@ -0,0 +1,119 @@
<script>
// The mini player window's root: boots the mirror, sizes the window to
// the chosen shape, and mounts it. The shared control classes (.m-disc,
// .m-skip, .m-mode) live here as :global so eight shapes speak one
// dialect — the disc is the app's one true play control (filled accent,
// padding: 0 against the UA-padding trap).
import { getCurrentWindow } from "@tauri-apps/api/window";
import { initMini, shapeState, setShape, mini } from "./mini.svelte.js";
import Strip from "./shapes/Strip.svelte";
import Sleeve from "./shapes/Sleeve.svelte";
import Sliver from "./shapes/Sliver.svelte";
import Wave from "./shapes/Wave.svelte";
import Focus from "./shapes/Focus.svelte";
import Deck from "./shapes/Deck.svelte";
import OnDeck from "./shapes/OnDeck.svelte";
import Queue from "./shapes/Queue.svelte";
const SHAPE_MAP = {
strip: Strip,
sleeve: Sleeve,
sliver: Sliver,
wave: Wave,
focus: Focus,
deck: Deck,
ondeck: OnDeck,
queue: Queue,
};
const Current = $derived(SHAPE_MAP[shapeState.id] ?? Strip);
initMini();
// Assert the stored shape's size on boot (the window opens with the
// last-known size from mini_open, which may belong to another shape).
void setShape(shapeState.id);
// Drag ANYWHERE to move the window — the whole mini is a titlebar except
// the things you actually operate. One owner for dragging: the shapes'
// data-tauri-drag-region patchwork is gone (the attribute only fires when
// the press lands ON the attributed element, so art, wash, padding and
// rows were all dead zones — "finicky").
const NO_DRAG =
"button, a, input, select, textarea, [role='slider'], .wave-wrap, .volwrap, .fly, .qlist, .picker, [data-nodrag]";
function dragAnywhere(e) {
if (e.button !== 0) return;
if (e.target.closest?.(NO_DRAG)) return;
void getCurrentWindow().startDragging();
}
</script>
<svelte:window onpointerdown={dragAnywhere} />
<div class="miniroot">
<Current />
</div>
<style>
/* The accent crossfade, the mini's way: --accent is a registered
@property (<color>), so a CSS transition interpolates it and every
var() consumer — plus the per-frame getComputedStyle readers in Lane
and Wave — rides one fade. Ease matches the main's t·(2−t) lerp. */
:global(html) {
transition:
--accent 1200ms cubic-bezier(0.25, 0.46, 0.45, 0.94),
--accent-hover 1200ms cubic-bezier(0.25, 0.46, 0.45, 0.94);
}
.miniroot {
width: 100vw;
height: 100vh;
overflow: hidden;
background: var(--bg-player);
user-select: none;
}
:global(.m-disc) {
border-radius: 50%;
background: var(--accent);
color: #0b0b0e;
display: grid;
place-items: center;
flex: none;
width: 34px;
height: 34px;
padding: 0; /* global.css leaves UA button padding on — never trust it */
transition: background 120ms, transform 120ms;
}
:global(.m-disc:hover) {
background: var(--accent-hover);
transform: scale(1.05);
}
:global(.m-disc.big) {
width: 44px;
height: 44px;
}
:global(.m-disc.small) {
width: 30px;
height: 30px;
}
:global(.m-skip) {
color: var(--text-secondary);
display: grid;
place-items: center;
padding: 0;
flex: none;
}
:global(.m-skip:hover) {
color: #fff;
}
:global(.m-mode) {
color: var(--text-muted);
display: grid;
place-items: center;
padding: 0;
flex: none;
}
:global(.m-mode:hover) {
color: var(--text-secondary);
}
:global(.m-mode.on) {
color: var(--accent);
}
</style>