feat: v1.11.0 — Movies themes, Settings polish, Gapless stable

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Psychotoxical
2026-03-22 02:37:49 +01:00
parent e550340565
commit 867c5fbd3e
27 changed files with 753 additions and 190 deletions
+2 -2
View File
@@ -59,8 +59,8 @@ export default function AlbumCard({ album }: AlbumCardProps) {
</div>
</div>
<div className="album-card-info">
<p className="album-card-title truncate" data-tooltip={album.name}>{album.name}</p>
<p className="album-card-artist truncate" data-tooltip={album.artist}>{album.artist}</p>
<p className="album-card-title truncate">{album.name}</p>
<p className="album-card-artist truncate">{album.artist}</p>
{album.year && <p className="album-card-year">{album.year}</p>}
</div>
</div>
+1 -1
View File
@@ -144,7 +144,7 @@ export default function AlbumTrackList({
: (song.track ?? i + 1)}
</div>
<div className="track-info">
<span className="track-title" data-tooltip={song.title}>{song.title}</span>
<span className="track-title">{song.title}</span>
</div>
{hasVariousArtists && (
<div className="track-artist-cell">
+1 -1
View File
@@ -31,7 +31,7 @@ export default function ArtistCardLocal({ artist }: Props) {
)}
</div>
<div className="artist-card-info">
<span className="artist-card-name" data-tooltip={artist.name}>{artist.name}</span>
<span className="artist-card-name">{artist.name}</span>
{typeof artist.albumCount === 'number' && (
<span className="artist-card-meta">
{artist.albumCount} {artist.albumCount === 1 ? 'Album' : 'Alben'}
-2
View File
@@ -75,7 +75,6 @@ export default function PlayerBar() {
<div className="player-track-meta">
<div
className="player-track-name"
data-tooltip={currentTrack?.title ?? ''}
style={{ cursor: currentTrack?.albumId ? 'pointer' : 'default' }}
onClick={() => currentTrack?.albumId && navigate(`/album/${currentTrack.albumId}`)}
>
@@ -83,7 +82,6 @@ export default function PlayerBar() {
</div>
<div
className="player-track-artist"
data-tooltip={currentTrack?.artist ?? ''}
style={{ cursor: currentTrack?.artistId ? 'pointer' : 'default' }}
onClick={() => currentTrack?.artistId && navigate(`/artist/${currentTrack.artistId}`)}
>
+1 -3
View File
@@ -329,16 +329,14 @@ export default function QueuePanel() {
)}
</div>
<div className="queue-current-info">
<h3 className="truncate" data-tooltip={currentTrack.title}>{currentTrack.title}</h3>
<h3 className="truncate">{currentTrack.title}</h3>
<div
className="queue-current-sub truncate"
data-tooltip={currentTrack.artist}
style={{ cursor: currentTrack.artistId ? 'pointer' : 'default' }}
onClick={() => currentTrack.artistId && navigate(`/artist/${currentTrack.artistId}`)}
>{currentTrack.artist}</div>
<div
className="queue-current-sub truncate"
data-tooltip={currentTrack.album}
style={{ cursor: currentTrack.albumId ? 'pointer' : 'default' }}
onClick={() => currentTrack.albumId && navigate(`/album/${currentTrack.albumId}`)}
>{currentTrack.album}</div>
+11 -1
View File
@@ -32,7 +32,7 @@ const THEME_GROUPS: { group: string; themes: ThemeDef[] }[] = [
],
},
{
group: 'Betriebssysteme',
group: 'Operating Systems',
themes: [
{ id: 'cupertino-light', label: 'Cupertino Light', bg: '#ffffff', card: '#f2f2f7', accent: '#0071e3' },
{ id: 'cupertino-dark', label: 'Cupertino Dark', bg: '#1e1e1f', card: '#2d2d2f', accent: '#007aff' },
@@ -77,6 +77,16 @@ const THEME_GROUPS: { group: string; themes: ThemeDef[] }[] = [
{ id: 'tokyo-night-light', label: 'Light', bg: '#d5d6db', card: '#e9e9ec', accent: '#34548a' },
],
},
{
group: 'Movies',
themes: [
{ id: 'middle-earth', label: 'Middle Earth', bg: '#f4e4bc', card: '#2a1d15', accent: '#d4af37' },
{ id: 'morpheus', label: 'Morpheus', bg: '#0a0a0a', card: '#000000', accent: '#00ff41' },
{ id: 'pandora', label: 'Pandora', bg: '#0c1b22', card: '#142b35', accent: '#00f2ff' },
{ id: 'stark-hud', label: 'Stark HUD', bg: '#0b0f15', card: '#05070a', accent: '#00f2ff' },
{ id: 'blade', label: 'Blade', bg: '#121212', card: '#050505', accent: '#b30000' },
],
},
];
interface Props {
+9 -2
View File
@@ -13,6 +13,9 @@ export default function TooltipPortal() {
const boxRef = useRef<HTMLDivElement>(null);
const [style, setStyle] = useState<React.CSSProperties>({ opacity: 0 });
const tooltipRef = useRef<TooltipState | null>(null);
tooltipRef.current = tooltip;
useEffect(() => {
const onOver = (e: MouseEvent) => {
const target = (e.target as HTMLElement).closest('[data-tooltip]') as HTMLElement | null;
@@ -26,15 +29,19 @@ export default function TooltipPortal() {
wrap: target.hasAttribute('data-tooltip-wrap'),
});
};
const onOut = (e: MouseEvent) => {
const onOut = () => setTooltip(null);
const onMove = (e: MouseEvent) => {
if (!tooltipRef.current) return;
const target = (e.target as HTMLElement).closest('[data-tooltip]');
if (target) setTooltip(null);
if (!target) setTooltip(null);
};
document.addEventListener('mouseover', onOver);
document.addEventListener('mouseout', onOut);
document.addEventListener('mousemove', onMove, { passive: true });
return () => {
document.removeEventListener('mouseover', onOver);
document.removeEventListener('mouseout', onOut);
document.removeEventListener('mousemove', onMove);
};
}, []);