Update FullScreenPlayer for improved iOS scrolling compatibility; adjust LibraryPage layout for better spacing and Card component padding
This commit is contained in:
@@ -1 +1 @@
|
|||||||
NEXT_PUBLIC_COMMIT_SHA=57c4070
|
NEXT_PUBLIC_COMMIT_SHA=a957398
|
||||||
|
|||||||
@@ -108,22 +108,55 @@ export const FullScreenPlayer: React.FC<FullScreenPlayerProps> = ({ isOpen, onCl
|
|||||||
|
|
||||||
if (currentLyricIndex >= 0 && shouldScroll && lyricsRef.current) {
|
if (currentLyricIndex >= 0 && shouldScroll && lyricsRef.current) {
|
||||||
const scrollTimeout = setTimeout(() => {
|
const scrollTimeout = setTimeout(() => {
|
||||||
// Find the ScrollArea viewport
|
// Try multiple selectors for better iOS compatibility
|
||||||
const scrollViewport = lyricsRef.current?.querySelector('[data-radix-scroll-area-viewport]') as HTMLElement;
|
let scrollContainer = lyricsRef.current?.querySelector('[data-radix-scroll-area-viewport]') as HTMLElement;
|
||||||
|
|
||||||
|
// Fallback for iOS - look for the actual scrollable container
|
||||||
|
if (!scrollContainer) {
|
||||||
|
scrollContainer = lyricsRef.current?.querySelector('.scrollable-area') as HTMLElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Another fallback - use the lyricsRef itself if it's scrollable
|
||||||
|
if (!scrollContainer && lyricsRef.current) {
|
||||||
|
const computedStyle = window.getComputedStyle(lyricsRef.current);
|
||||||
|
if (computedStyle.overflowY === 'auto' || computedStyle.overflowY === 'scroll') {
|
||||||
|
scrollContainer = lyricsRef.current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Final fallback - look for any scrollable parent
|
||||||
|
if (!scrollContainer) {
|
||||||
|
let element = lyricsRef.current?.parentElement;
|
||||||
|
while (element) {
|
||||||
|
const computedStyle = window.getComputedStyle(element);
|
||||||
|
if (computedStyle.overflowY === 'auto' || computedStyle.overflowY === 'scroll') {
|
||||||
|
scrollContainer = element;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
element = element.parentElement;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const currentLyricElement = lyricsRef.current?.querySelector(`[data-lyric-index="${currentLyricIndex}"]`) as HTMLElement;
|
const currentLyricElement = lyricsRef.current?.querySelector(`[data-lyric-index="${currentLyricIndex}"]`) as HTMLElement;
|
||||||
|
|
||||||
if (scrollViewport && currentLyricElement) {
|
if (scrollContainer && currentLyricElement) {
|
||||||
const containerHeight = scrollViewport.clientHeight;
|
const containerHeight = scrollContainer.clientHeight;
|
||||||
const elementTop = currentLyricElement.offsetTop;
|
const elementTop = currentLyricElement.offsetTop;
|
||||||
const elementHeight = currentLyricElement.offsetHeight;
|
const elementHeight = currentLyricElement.offsetHeight;
|
||||||
|
|
||||||
// Calculate scroll position to center the current lyric
|
// Calculate scroll position to center the current lyric
|
||||||
const targetScrollTop = elementTop - (containerHeight / 2) + (elementHeight / 2);
|
const targetScrollTop = elementTop - (containerHeight / 2) + (elementHeight / 2);
|
||||||
|
|
||||||
scrollViewport.scrollTo({
|
// Use both scrollTo and scrollTop for better iOS compatibility
|
||||||
top: Math.max(0, targetScrollTop),
|
try {
|
||||||
behavior: 'smooth'
|
scrollContainer.scrollTo({
|
||||||
});
|
top: Math.max(0, targetScrollTop),
|
||||||
|
behavior: 'smooth'
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
// Fallback for older iOS versions
|
||||||
|
scrollContainer.scrollTop = Math.max(0, targetScrollTop);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, 100);
|
}, 100);
|
||||||
|
|
||||||
@@ -136,15 +169,48 @@ export const FullScreenPlayer: React.FC<FullScreenPlayerProps> = ({ isOpen, onCl
|
|||||||
const shouldReset = isMobile ? (activeTab === 'lyrics' && lyrics.length > 0) : (showLyrics && lyrics.length > 0);
|
const shouldReset = isMobile ? (activeTab === 'lyrics' && lyrics.length > 0) : (showLyrics && lyrics.length > 0);
|
||||||
|
|
||||||
if (currentTrack && shouldReset && lyricsRef.current) {
|
if (currentTrack && shouldReset && lyricsRef.current) {
|
||||||
// Reset scroll position using lyricsRef
|
// Reset scroll position using lyricsRef with iOS compatibility
|
||||||
const resetScroll = () => {
|
const resetScroll = () => {
|
||||||
const scrollViewport = lyricsRef.current?.querySelector('[data-radix-scroll-area-viewport]') as HTMLElement;
|
// Try multiple selectors for better iOS compatibility
|
||||||
|
let scrollContainer = lyricsRef.current?.querySelector('[data-radix-scroll-area-viewport]') as HTMLElement;
|
||||||
|
|
||||||
if (scrollViewport) {
|
// Fallback for iOS - look for the actual scrollable container
|
||||||
scrollViewport.scrollTo({
|
if (!scrollContainer) {
|
||||||
top: 0,
|
scrollContainer = lyricsRef.current?.querySelector('.scrollable-area') as HTMLElement;
|
||||||
behavior: 'instant' // Use instant for track changes
|
}
|
||||||
});
|
|
||||||
|
// Another fallback - use the lyricsRef itself if it's scrollable
|
||||||
|
if (!scrollContainer && lyricsRef.current) {
|
||||||
|
const computedStyle = window.getComputedStyle(lyricsRef.current);
|
||||||
|
if (computedStyle.overflowY === 'auto' || computedStyle.overflowY === 'scroll') {
|
||||||
|
scrollContainer = lyricsRef.current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Final fallback - look for any scrollable parent
|
||||||
|
if (!scrollContainer) {
|
||||||
|
let element = lyricsRef.current?.parentElement;
|
||||||
|
while (element) {
|
||||||
|
const computedStyle = window.getComputedStyle(element);
|
||||||
|
if (computedStyle.overflowY === 'auto' || computedStyle.overflowY === 'scroll') {
|
||||||
|
scrollContainer = element;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
element = element.parentElement;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scrollContainer) {
|
||||||
|
// Use both scrollTo and scrollTop for better iOS compatibility
|
||||||
|
try {
|
||||||
|
scrollContainer.scrollTo({
|
||||||
|
top: 0,
|
||||||
|
behavior: 'instant' // Use instant for track changes
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
// Fallback for older iOS versions
|
||||||
|
scrollContainer.scrollTop = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -500,8 +566,15 @@ export const FullScreenPlayer: React.FC<FullScreenPlayerProps> = ({ isOpen, onCl
|
|||||||
|
|
||||||
{activeTab === 'lyrics' && lyrics.length > 0 && (
|
{activeTab === 'lyrics' && lyrics.length > 0 && (
|
||||||
<div className="h-full flex flex-col px-4">
|
<div className="h-full flex flex-col px-4">
|
||||||
<ScrollArea className="flex-1">
|
<div
|
||||||
<div className="space-y-3 py-4" ref={lyricsRef}>
|
className="flex-1 overflow-y-auto scrollable-area"
|
||||||
|
ref={lyricsRef}
|
||||||
|
style={{
|
||||||
|
WebkitOverflowScrolling: 'touch', // Enable momentum scrolling on iOS
|
||||||
|
scrollBehavior: 'smooth'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="space-y-3 py-4">
|
||||||
{lyrics.map((line, index) => (
|
{lyrics.map((line, index) => (
|
||||||
<div
|
<div
|
||||||
key={index}
|
key={index}
|
||||||
@@ -527,7 +600,7 @@ export const FullScreenPlayer: React.FC<FullScreenPlayerProps> = ({ isOpen, onCl
|
|||||||
))}
|
))}
|
||||||
<div style={{ height: '200px' }} />
|
<div style={{ height: '200px' }} />
|
||||||
</div>
|
</div>
|
||||||
</ScrollArea>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
@@ -162,13 +162,13 @@ export default function LibraryPage() {
|
|||||||
{/* Library Navigation - Always at top */}
|
{/* Library Navigation - Always at top */}
|
||||||
<div>
|
<div>
|
||||||
<h2 className="text-lg font-semibold mb-3">Browse</h2>
|
<h2 className="text-lg font-semibold mb-3">Browse</h2>
|
||||||
<div className="space-y-3">
|
<div className="flex flex-col gap-2">
|
||||||
{libraryLinks.map((link) => {
|
{libraryLinks.map((link) => {
|
||||||
const Icon = link.icon;
|
const Icon = link.icon;
|
||||||
return (
|
return (
|
||||||
<Link key={link.href} href={link.href}>
|
<Link key={link.href} href={link.href}>
|
||||||
<Card className="hover:bg-muted/50 transition-colors cursor-pointer">
|
<Card className="hover:bg-muted/50 transition-colors cursor-pointer">
|
||||||
<CardContent className="p-4">
|
<CardContent className="p-2">
|
||||||
<div className="flex items-center space-x-4">
|
<div className="flex items-center space-x-4">
|
||||||
<div className="p-2 bg-primary/10 rounded-lg">
|
<div className="p-2 bg-primary/10 rounded-lg">
|
||||||
<Icon className="w-6 h-6 text-primary" />
|
<Icon className="w-6 h-6 text-primary" />
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ function Card({ className, ...props }: React.ComponentProps<"div">) {
|
|||||||
<div
|
<div
|
||||||
data-slot="card"
|
data-slot="card"
|
||||||
className={cn(
|
className={cn(
|
||||||
"bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",
|
"bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-0 shadow-sm",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
Reference in New Issue
Block a user