Add square cover toggle and UI support

Introduce a SquareCoversToggle component and wire cover-aspect switching throughout the app. PreferencesContext now stores and persists a new squareCovers flag (with cross-tab sync), and pages (Home, Search) expose the toggle and pass the squareCovers prop to AudiobookGrid/AudiobookCard. AudiobookCard/Grid and skeletons were updated to respect square vs 2:3 aspect ratios and include smoother transitions. Also update app icons/manifest references to RMAB_1024x1024_ICON.png and make header/branding responsive (truncate titles, adjust version badge placement and logo usage). Minor UI/UX tweaks added for accessibility and visual polish.
This commit is contained in:
kikootwo
2026-02-04 19:50:39 -05:00
parent 1cb77dc989
commit fe39831ada
10 changed files with 138 additions and 28 deletions
+6 -2
View File
@@ -19,6 +19,7 @@ interface AudiobookCardProps {
isRequested?: boolean;
requestStatus?: string;
onRequestSuccess?: () => void;
squareCovers?: boolean;
}
export function AudiobookCard({
@@ -26,6 +27,7 @@ export function AudiobookCard({
isRequested = false,
requestStatus,
onRequestSuccess,
squareCovers = false,
}: AudiobookCardProps) {
const { user } = useAuth();
const { createRequest, isLoading } = useCreateRequest();
@@ -59,10 +61,12 @@ export function AudiobookCard({
return (
<>
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-md overflow-hidden hover:shadow-lg transition-shadow">
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-md overflow-hidden hover:shadow-lg transition-all duration-300">
{/* Cover Art - Clickable */}
<div
className="relative aspect-[2/3] bg-gray-200 dark:bg-gray-700 cursor-pointer group"
className={`relative bg-gray-200 dark:bg-gray-700 cursor-pointer group overflow-hidden ${
squareCovers ? 'aspect-square' : 'aspect-[2/3]'
}`}
onClick={() => setShowModal(true)}
>
{audiobook.coverArtUrl ? (
+10 -5
View File
@@ -15,6 +15,7 @@ interface AudiobookGridProps {
emptyMessage?: string;
onRequestSuccess?: () => void;
cardSize?: number; // 1-9, default 5
squareCovers?: boolean; // true = square (1:1), false = rectangle (2:3)
}
// Helper function to get grid classes based on card size
@@ -41,6 +42,7 @@ export function AudiobookGrid({
emptyMessage = 'No audiobooks found',
onRequestSuccess,
cardSize = 5,
squareCovers = false,
}: AudiobookGridProps) {
const gridClasses = getGridClasses(cardSize);
@@ -48,7 +50,7 @@ export function AudiobookGrid({
return (
<div className={`grid ${gridClasses} gap-3 sm:gap-4 md:gap-6`}>
{Array.from({ length: 8 }).map((_, i) => (
<SkeletonCard key={i} />
<SkeletonCard key={i} squareCovers={squareCovers} />
))}
</div>
);
@@ -76,23 +78,26 @@ export function AudiobookGrid({
}
return (
<div className={`grid ${gridClasses} gap-3 sm:gap-4 md:gap-6`}>
<div className={`grid ${gridClasses} gap-3 sm:gap-4 md:gap-6 transition-all duration-300`}>
{audiobooks.map((audiobook) => (
<AudiobookCard
key={audiobook.asin}
audiobook={audiobook}
onRequestSuccess={onRequestSuccess}
squareCovers={squareCovers}
/>
))}
</div>
);
}
function SkeletonCard() {
function SkeletonCard({ squareCovers = false }: { squareCovers?: boolean }) {
return (
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-md overflow-hidden animate-pulse">
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-md overflow-hidden animate-pulse transition-all duration-300">
{/* Cover Art Skeleton */}
<div className="aspect-[2/3] bg-gray-200 dark:bg-gray-700" />
<div className={`bg-gray-200 dark:bg-gray-700 ${
squareCovers ? 'aspect-square' : 'aspect-[2/3]'
}`} />
{/* Content Skeleton */}
<div className="p-4 space-y-3">