| @@ -343,7 +343,15 @@ export default function AdminDashboard() { | |||||
| // CHANGED: flex-col on mobile, flex-row on sm+, added gap-4 for mobile spacing | // CHANGED: flex-col on mobile, flex-row on sm+, added gap-4 for mobile spacing | ||||
| <div key={card.id} className="flex flex-col sm:flex-row sm:items-center justify-between p-4 border rounded-lg bg-gray-50 hover:bg-gray-100 transition-colors gap-4"> | <div key={card.id} className="flex flex-col sm:flex-row sm:items-center justify-between p-4 border rounded-lg bg-gray-50 hover:bg-gray-100 transition-colors gap-4"> | ||||
| <div className="flex items-center gap-4"> | <div className="flex items-center gap-4"> | ||||
| {card.imageUrl ? <img src={card.imageUrl} className="w-16 h-16 object-cover rounded-md shadow-sm shrink-0" alt="" /> : <div className="w-16 h-16 bg-gray-200 rounded-md shadow-sm flex items-center justify-center text-gray-400 text-xs shrink-0">No Image</div>} | |||||
| {(() => { | |||||
| const previewUrl = card.imageUrl || card.extraMedia?.[0]?.url || ''; | |||||
| if (!previewUrl) { | |||||
| return <div className="w-16 h-16 bg-gray-200 rounded-md shadow-sm flex items-center justify-center text-gray-400 text-xs shrink-0">No Image</div>; | |||||
| } | |||||
| return isVideoUrl(previewUrl) | |||||
| ? <video src={previewUrl} className="w-16 h-16 object-cover rounded-md shadow-sm shrink-0" muted playsInline preload="metadata" /> | |||||
| : <img src={previewUrl} className="w-16 h-16 object-cover rounded-md shadow-sm shrink-0" alt="" />; | |||||
| })()} | |||||
| <div> | <div> | ||||
| <span className="font-semibold text-gray-800 block">{card.title}</span> | <span className="font-semibold text-gray-800 block">{card.title}</span> | ||||
| <span className="text-xs text-gray-500 uppercase tracking-wider">{card.cardType}</span> | <span className="text-xs text-gray-500 uppercase tracking-wider">{card.cardType}</span> | ||||
| @@ -453,6 +453,9 @@ export default function PublicGrid({ cards, maxCols = 5 }: { cards: Card[], maxC | |||||
| <div className={`grid gap-4 ${activeGridClass}`}> | <div className={`grid gap-4 ${activeGridClass}`}> | ||||
| {cards.map((card) => { | {cards.map((card) => { | ||||
| const galleryCount = (card.extraMedia?.length || 0) + (card.imageUrl ? 1 : 0); | const galleryCount = (card.extraMedia?.length || 0) + (card.imageUrl ? 1 : 0); | ||||
| // Fall back to the first gallery item when no explicit cover is set. | |||||
| const previewUrl = card.imageUrl || card.extraMedia?.[0]?.url || ''; | |||||
| const previewIsVideo = !!previewUrl && isVideoUrl(previewUrl); | |||||
| return ( | return ( | ||||
| <div | <div | ||||
| key={card.id} | key={card.id} | ||||
| @@ -462,8 +465,18 @@ export default function PublicGrid({ cards, maxCols = 5 }: { cards: Card[], maxC | |||||
| }} | }} | ||||
| className="group relative cursor-pointer overflow-hidden rounded-xl shadow-md aspect-square bg-gray-200 transition-all duration-300 hover:shadow-xl hover:-translate-y-1" | className="group relative cursor-pointer overflow-hidden rounded-xl shadow-md aspect-square bg-gray-200 transition-all duration-300 hover:shadow-xl hover:-translate-y-1" | ||||
| > | > | ||||
| {card.imageUrl ? ( | |||||
| <img src={card.imageUrl} alt={card.title} className="absolute inset-0 w-full h-full object-cover" /> | |||||
| {previewUrl ? ( | |||||
| previewIsVideo ? ( | |||||
| <video | |||||
| src={previewUrl} | |||||
| className="absolute inset-0 w-full h-full object-cover pointer-events-none" | |||||
| muted | |||||
| playsInline | |||||
| preload="metadata" | |||||
| /> | |||||
| ) : ( | |||||
| <img src={previewUrl} alt={card.title} className="absolute inset-0 w-full h-full object-cover" /> | |||||
| ) | |||||
| ) : ( | ) : ( | ||||
| <div className="absolute inset-0 flex items-center justify-center bg-gradient-to-br from-blue-100 to-gray-200 text-gray-400">No Image</div> | <div className="absolute inset-0 flex items-center justify-center bg-gradient-to-br from-blue-100 to-gray-200 text-gray-400">No Image</div> | ||||
| )} | )} | ||||