fix(ui): shrink-wrap floating player bar instead of full-width strip (#969)

* fix(ui): shrink-wrap floating player bar instead of full-width strip

The bar used fixed left and right insets, which stretched its background
across the whole main column. Center it with max-content width so only
the pill-shaped controls are painted, and soften the drop shadow.

* docs: note PR #969 in changelog and settings credits
This commit is contained in:
cucadmuh
2026-06-04 00:03:24 +03:00
committed by GitHub
parent e8962c21ab
commit c9b2d140d9
7 changed files with 65 additions and 14 deletions
@@ -0,0 +1,19 @@
import { describe, expect, it } from 'vitest';
import { computeFloatingPlayerBarStyle } from './computeFloatingPlayerBarStyle';
describe('computeFloatingPlayerBarStyle', () => {
it('centers in the main column and shrink-wraps instead of stretching', () => {
const style = computeFloatingPlayerBarStyle(220, 1600, 1920);
expect(style.left).toBe(910);
expect(style.right).toBe('auto');
expect(style.transform).toBe('translateX(-50%)');
expect(style.width).toBe('max-content');
expect(style.maxWidth).toBe(1332);
});
it('accounts for a hidden queue panel', () => {
const style = computeFloatingPlayerBarStyle(220, null, 1920);
expect(style.left).toBe(1070);
expect(style.maxWidth).toBe(1652);
});
});
@@ -0,0 +1,24 @@
import type { CSSProperties } from 'react';
const HORIZONTAL_MARGIN_PX = 24;
/** Center the floating bar in the main column; shrink-wrap width instead of stretching. */
export function computeFloatingPlayerBarStyle(
sidebarRight: number,
queueLeft: number | null,
viewportWidth: number,
): CSSProperties {
const contentLeft = sidebarRight;
const contentRight = queueLeft ?? viewportWidth;
const contentWidth = Math.max(0, contentRight - contentLeft);
const maxWidth = Math.max(100, contentWidth - HORIZONTAL_MARGIN_PX * 2);
const centerX = contentLeft + contentWidth / 2;
return {
left: centerX,
right: 'auto',
transform: 'translateX(-50%)',
width: 'max-content',
maxWidth,
};
}
+6 -9
View File
@@ -1,4 +1,5 @@
import React, { useEffect, useState } from 'react';
import { computeFloatingPlayerBarStyle } from './computeFloatingPlayerBarStyle';
/** Computes the floating player-bar position based on the current sidebar +
* queue panel widths. Returns an inline-style object (left/right/width); only
@@ -14,17 +15,13 @@ export function useFloatingPlayerBar(
if (!floatingPlayerBar) return;
const updatePosition = () => {
const sidebar = document.querySelector('.sidebar') as HTMLElement;
const queue = document.querySelector('.queue-panel') as HTMLElement;
const sidebar = document.querySelector('.sidebar') as HTMLElement | null;
const queue = document.querySelector('.queue-panel') as HTMLElement | null;
const leftOffset = sidebar ? sidebar.getBoundingClientRect().right : 0;
const rightOffset = queue ? window.innerWidth - queue.getBoundingClientRect().left : 0;
const sidebarRight = sidebar ? sidebar.getBoundingClientRect().right : 0;
const queueLeft = queue ? queue.getBoundingClientRect().left : null;
setFloatingStyle({
left: leftOffset + 24,
right: rightOffset + 24,
width: 'auto',
});
setFloatingStyle(computeFloatingPlayerBarStyle(sidebarRight, queueLeft, window.innerWidth));
};
updatePosition();