new
This commit is contained in:
@@ -1,13 +1,15 @@
|
||||
|
||||
import React from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
import { CalendarOutlined, RightOutlined } from '@ant-design/icons';
|
||||
import { CalendarOutlined } from '@ant-design/icons';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import styles from './activity.module.less';
|
||||
import { hoverScale, imageFadeIn } from '../../animation';
|
||||
import { hoverScale } from '../../animation';
|
||||
|
||||
const ActivityCard = ({ activity, index }) => {
|
||||
const ActivityCard = ({ activity }) => {
|
||||
const navigate = useNavigate();
|
||||
const [isLoaded, setIsLoaded] = useState(false);
|
||||
const [hasError, setHasError] = useState(false);
|
||||
|
||||
const handleCardClick = () => {
|
||||
navigate(`/activity/${activity.id}`);
|
||||
@@ -17,7 +19,6 @@ const ActivityCard = ({ activity, index }) => {
|
||||
const now = new Date();
|
||||
const start = new Date(startTime);
|
||||
if (now < start) return '即将开始';
|
||||
// Simple logic, can be enhanced
|
||||
return '报名中';
|
||||
};
|
||||
|
||||
@@ -27,6 +28,10 @@ const ActivityCard = ({ activity, index }) => {
|
||||
return date.toLocaleDateString('zh-CN', { month: 'long', day: 'numeric' });
|
||||
};
|
||||
|
||||
const imgSrc = hasError
|
||||
? 'https://via.placeholder.com/600x400?text=No+Image'
|
||||
: (activity.display_banner_url || activity.banner_url || activity.cover_image || 'https://via.placeholder.com/600x400');
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
className={styles.activityCard}
|
||||
@@ -37,13 +42,31 @@ const ActivityCard = ({ activity, index }) => {
|
||||
style={{ willChange: 'transform' }}
|
||||
>
|
||||
<div className={styles.imageContainer}>
|
||||
{/* Placeholder / Skeleton Background */}
|
||||
<div
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
backgroundColor: '#f0f0f0',
|
||||
opacity: isLoaded ? 0 : 1,
|
||||
transition: 'opacity 0.5s ease'
|
||||
}}
|
||||
/>
|
||||
|
||||
<motion.img
|
||||
src={activity.display_banner_url || activity.banner_url || activity.cover_image || 'https://via.placeholder.com/600x400'}
|
||||
src={imgSrc}
|
||||
alt={activity.title}
|
||||
variants={imageFadeIn}
|
||||
initial="hidden"
|
||||
whileInView="visible"
|
||||
viewport={{ once: true }}
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: isLoaded ? 1 : 0 }}
|
||||
transition={{ duration: 0.5 }}
|
||||
onLoad={() => setIsLoaded(true)}
|
||||
onError={() => {
|
||||
setHasError(true);
|
||||
setIsLoaded(true); // Show placeholder image
|
||||
}}
|
||||
loading="lazy"
|
||||
/>
|
||||
<div className={styles.overlay}>
|
||||
|
||||
Reference in New Issue
Block a user