133 lines
4.5 KiB
Svelte
133 lines
4.5 KiB
Svelte
<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;
|
||
}
|
||
/* Dark glass, mini edition: unlike the main window (only the canvas
|
||
BETWEEN panes thins), the mini is all pane — so the pane itself thins
|
||
to the same black tint the main's .app uses (one dial, two files —
|
||
keep the alphas in step), over the OS acrylic (window_glass).
|
||
global.css already stops html/body painting under .glass; every
|
||
shape's own --bg-player fill is overridden in one place here. The
|
||
Wash art bleed stays as-is above it. */
|
||
:global(:root.glass) .miniroot {
|
||
background: transparent;
|
||
}
|
||
:global(:root.glass) .miniroot :global(.shape) {
|
||
background: rgba(0, 0, 0, 0.55);
|
||
}
|
||
: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>
|