hookehuyr

refactor(ui): 删除不再使用的UI组件

清理代码库中不再使用的UI组件,包括FrostedGlass、SearchBar、CourseCard、GradientHeader、LiveStreamCard、SummerCampCard和ActivityCard。这些组件在当前项目中已无作用,删除以保持代码简洁。
1 -import React from 'react';
2 -import { Link } from 'react-router-dom';
3 -import FrostedGlass from './FrostedGlass';
4 -
5 -/**
6 - * ActivityCard component displays an activity item in the activities list
7 - *
8 - * @param {Object} props - Component props
9 - * @param {Object} props.activity - Activity data
10 - * @returns {JSX.Element} ActivityCard component
11 - */
12 -const ActivityCard = ({ activity }) => {
13 - // Function to get the appropriate status class
14 - const getStatusClass = (status) => {
15 - switch (status) {
16 - case '活动中':
17 - return 'bg-blue-100 text-blue-600';
18 - case '进行中':
19 - return 'bg-green-100 text-green-600';
20 - case '即将开始':
21 - return 'bg-orange-100 text-orange-600';
22 - case '已结束':
23 - return 'bg-gray-100 text-gray-600';
24 - default:
25 - return 'bg-gray-100 text-gray-600';
26 - }
27 - };
28 -
29 - return (
30 - <Link to={`/activities/${activity.id}`}>
31 - <FrostedGlass className="flex overflow-hidden rounded-xl shadow-sm">
32 - {/* Activity Image */}
33 - <div className="w-1/3 h-28 relative">
34 - <img
35 - src={activity.imageUrl}
36 - alt={activity.title}
37 - className="w-full h-full object-cover"
38 - />
39 - {activity.isHot && (
40 - <div className="absolute top-0 left-0 bg-red-500 text-white text-xs px-2 py-0.5">
41 - 热门
42 - </div>
43 - )}
44 - </div>
45 -
46 - {/* Activity Info */}
47 - <div className="flex-1 p-3 flex flex-col justify-between">
48 - <div>
49 - <h3 className="font-medium text-base mb-1 line-clamp-1">{activity.title}</h3>
50 -
51 - {/* Status Tags */}
52 - <div className="flex items-center space-x-2 mb-1">
53 - <span className={`px-2 py-0.5 rounded-full text-xs ${getStatusClass(activity.status)}`}>
54 - {activity.status}
55 - </span>
56 - {activity.isFree && (
57 - <span className="px-2 py-0.5 rounded-full text-xs bg-green-100 text-green-600">
58 - 免费
59 - </span>
60 - )}
61 - </div>
62 - </div>
63 -
64 - {/* Location and Time */}
65 - <div className="text-xs text-gray-500 space-y-1">
66 - <div className="flex items-center">
67 - <svg xmlns="http://www.w3.org/2000/svg" className="h-3.5 w-3.5 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
68 - <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z" />
69 - <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 11a3 3 0 11-6 0 3 3 0 016 0z" />
70 - </svg>
71 - <span>{activity.location}</span>
72 - </div>
73 -
74 - <div className="flex items-center">
75 - <svg xmlns="http://www.w3.org/2000/svg" className="h-3.5 w-3.5 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
76 - <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
77 - </svg>
78 - <span>{activity.period}</span>
79 - </div>
80 - </div>
81 -
82 - {/* Bottom Info Section */}
83 - <div className="mt-1 flex items-center justify-between">
84 - {activity.price ? (
85 - <div className="flex items-baseline">
86 - <span className="text-red-500 font-medium">¥{activity.price}</span>
87 - {activity.originalPrice && (
88 - <span className="text-xs text-gray-400 ml-1 line-through">¥{activity.originalPrice}</span>
89 - )}
90 - </div>
91 - ) : (
92 - <div></div> // Empty div for spacing when no price
93 - )}
94 -
95 - <div className="flex items-center text-xs text-gray-500">
96 - <svg xmlns="http://www.w3.org/2000/svg" className="h-3.5 w-3.5 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
97 - <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z" />
98 - </svg>
99 - <span>{activity.participantsCount || '15'}/{activity.maxParticipants || '30'}</span>
100 - </div>
101 - </div>
102 - </div>
103 - </FrostedGlass>
104 - </Link>
105 - );
106 -};
107 -
108 -export default ActivityCard;
...\ No newline at end of file ...\ No newline at end of file
1 -import React from 'react';
2 -import { Link } from 'react-router-dom';
3 -
4 -/**
5 - * CourseCard component displays a course item in the course list
6 - *
7 - * @param {Object} props - Component props
8 - * @param {Object} props.course - Course data
9 - * @returns {JSX.Element} CourseCard component
10 - */
11 -const CourseCard = ({ course }) => {
12 - return (
13 - <Link to={`/courses/${course.id}`} className="flex bg-white rounded-lg overflow-hidden shadow-sm">
14 - <div className="w-1/3 h-28">
15 - <img
16 - src={course.imageUrl}
17 - alt={course.title}
18 - className="w-full h-full object-cover"
19 - />
20 - </div>
21 - <div className="flex-1 p-3 flex flex-col justify-between">
22 - <div>
23 - <h3 className="font-medium text-sm mb-1 line-clamp-2">{course.title}</h3>
24 - <div className="text-gray-500 text-xs">{course.subtitle}</div>
25 - </div>
26 - <div className="flex justify-between items-end mt-1">
27 - <div className="text-orange-500 font-semibold">¥{course.price}</div>
28 - <div className="text-gray-400 text-xs">
29 - {course.subscribers}人订阅
30 - </div>
31 - </div>
32 - <div className="text-gray-400 text-xs">
33 - 已更新{course.updatedLessons}期 | {course.subscribers}人订阅
34 - </div>
35 - </div>
36 - </Link>
37 - );
38 -};
39 -
40 -export default CourseCard;
...\ No newline at end of file ...\ No newline at end of file
1 -import React from 'react';
2 -
3 -/**
4 - * FrostedGlass component creates a container with a frosted glass effect
5 - * using backdrop-filter blur and a semi-transparent white background.
6 - *
7 - * @param {Object} props - Component props
8 - * @param {ReactNode} props.children - Child elements
9 - * @param {string} props.className - Additional CSS classes
10 - * @returns {JSX.Element} FrostedGlass component
11 - */
12 -const FrostedGlass = ({ children, className = '' }) => {
13 - return (
14 - <div
15 - className={`bg-white/20 backdrop-blur-md rounded-xl border border-white/30
16 - shadow-lg ${className}`}
17 - >
18 - {children}
19 - </div>
20 - );
21 -};
22 -
23 -export default FrostedGlass;
...\ No newline at end of file ...\ No newline at end of file
1 -import React from 'react';
2 -
3 -/**
4 - * GradientHeader component for page headers with gradient background
5 - * and navigation elements.
6 - *
7 - * @param {Object} props - Component props
8 - * @param {string} props.title - Header title
9 - * @param {boolean} props.showBackButton - Whether to show back button
10 - * @param {Function} props.onBack - Back button click handler
11 - * @param {ReactNode} props.rightContent - Content to display on the right side
12 - * @returns {JSX.Element} GradientHeader component
13 - */
14 -const GradientHeader = ({ title, showBackButton = false, onBack, rightContent }) => {
15 - return (
16 - <header className="bg-gradient-to-r from-green-50 to-blue-50 p-4 relative">
17 - <div className="flex items-center justify-between">
18 - {showBackButton && (
19 - <button
20 - onClick={onBack}
21 - className="p-2 rounded-full bg-white/30 backdrop-blur-sm"
22 - aria-label="返回"
23 - >
24 - <svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 text-gray-700" fill="none" viewBox="0 0 24 24" stroke="currentColor">
25 - <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
26 - </svg>
27 - </button>
28 - )}
29 - <h1 className={`text-xl font-medium text-center ${showBackButton ? 'flex-1' : ''}`}>
30 - {title}
31 - </h1>
32 - {rightContent && <div>{rightContent}</div>}
33 - </div>
34 - </header>
35 - );
36 -};
37 -
38 -export default GradientHeader;
...\ No newline at end of file ...\ No newline at end of file
1 -import React from 'react';
2 -import { Link } from 'react-router-dom';
3 -
4 -/**
5 - * LiveStreamCard component displays a live stream in the courses page
6 - *
7 - * @param {Object} props - Component props
8 - * @param {Object} props.stream - Stream data
9 - * @returns {JSX.Element} LiveStreamCard component
10 - */
11 -const LiveStreamCard = ({ stream }) => {
12 - return (
13 - <div className="relative">
14 - {/* Live indicator */}
15 - <div className="absolute top-2 left-2 bg-red-500/90 text-white text-xs px-2 py-1 rounded flex items-center z-10">
16 - <div className="w-2 h-2 bg-white rounded-full mr-1 animate-pulse"></div>
17 - 直播中
18 - </div>
19 -
20 - <Link to={`/courses/${stream.id}`} className="block rounded-lg overflow-hidden shadow-sm relative">
21 - <img
22 - src={stream.imageUrl}
23 - alt={stream.title}
24 - className="w-full h-28 object-cover"
25 - />
26 -
27 - {/* Gradient overlay */}
28 - <div className="absolute inset-0 bg-gradient-to-b from-transparent to-black/60"></div>
29 -
30 - {/* Stream info */}
31 - <div className="absolute bottom-2 left-2 right-2">
32 - <h3 className="text-white text-sm font-medium">{stream.title}{stream.subtitle}</h3>
33 - <div className="flex items-center mt-1">
34 - <div className="flex -space-x-2">
35 - <div className="w-5 h-5 rounded-full bg-gray-300 border border-white"></div>
36 - <div className="w-5 h-5 rounded-full bg-gray-400 border border-white"></div>
37 - <div className="w-5 h-5 rounded-full bg-gray-500 border border-white"></div>
38 - </div>
39 - <span className="text-white text-xs ml-1">{stream.viewers}人在看</span>
40 - <button className="ml-auto bg-green-500 text-white text-xs px-2 py-1 rounded">
41 - 立即观看
42 - </button>
43 - </div>
44 - </div>
45 - </Link>
46 - </div>
47 - );
48 -};
49 -
50 -export default LiveStreamCard;
...\ No newline at end of file ...\ No newline at end of file
1 -import React from 'react';
2 -import FrostedGlass from './FrostedGlass';
3 -
4 -/**
5 - * SearchBar component with frosted glass effect
6 - *
7 - * @param {Object} props - Component props
8 - * @param {string} props.placeholder - Placeholder text
9 - * @param {Function} props.onSearch - Search callback function
10 - * @returns {JSX.Element} SearchBar component
11 - */
12 -const SearchBar = ({ placeholder = '搜索', onSearch }) => {
13 - return (
14 - <FrostedGlass className="px-4 py-2 mx-4 my-3 flex items-center">
15 - <svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 text-gray-400 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
16 - <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
17 - </svg>
18 - <input
19 - type="text"
20 - placeholder={placeholder}
21 - className="bg-transparent outline-none flex-1 text-gray-700 placeholder-gray-400"
22 - onChange={(e) => onSearch && onSearch(e.target.value)}
23 - />
24 - </FrostedGlass>
25 - );
26 -};
27 -
28 -export default SearchBar;
...\ No newline at end of file ...\ No newline at end of file
1 -import React from 'react';
2 -import PropTypes from 'prop-types';
3 -
4 -/**
5 - * SummerCampCard component - displays summer camp information with image background
6 - * @param {Object} props - Component props
7 - * @returns {JSX.Element} - Rendered component
8 - */
9 -const SummerCampCard = ({
10 - title = "大国少年-世界正东方",
11 - subtitle = "亲子夏令营",
12 - badge = "亲子夏令营",
13 - price = "¥1280",
14 - discount = "限时优惠",
15 - episodes = 16,
16 - subscribers = 1140
17 -}) => {
18 - return (
19 - <div className="relative overflow-hidden rounded-b-3xl shadow-lg">
20 - {/* Background image with overlay */}
21 - <div
22 - className="absolute inset-0 z-0 bg-cover bg-center"
23 - style={{
24 - backgroundImage: `url('/assets/images/summer-camp.jpg')`,
25 - filter: 'brightness(0.4)'
26 - }}
27 - ></div>
28 -
29 - {/* Gradient overlay */}
30 - <div className="absolute inset-0 z-1 bg-gradient-to-b from-red-500/70 to-red-600/90"></div>
31 -
32 - {/* Content */}
33 - <div className="relative z-10 p-4">
34 - <div className="bg-white/10 backdrop-blur-sm rounded-lg p-3 mb-3 inline-block">
35 - <div className="text-white font-semibold">{badge}</div>
36 - </div>
37 -
38 - <h1 className="text-2xl text-white font-bold mb-1">{title}</h1>
39 - <h2 className="text-lg text-white/90">{subtitle}</h2>
40 -
41 - <div className="mt-4 flex justify-between items-center">
42 - <div className="text-orange-300 font-bold text-2xl">{price}</div>
43 - <div className="bg-orange-500/30 text-orange-100 text-xs px-3 py-1 rounded-full">{discount}</div>
44 - </div>
45 -
46 - <div className="flex justify-between text-xs text-white/80 mt-3">
47 - <div>已更新{episodes}</div>
48 - <div>{subscribers}人订阅</div>
49 - </div>
50 - </div>
51 - </div>
52 - );
53 -};
54 -
55 -SummerCampCard.propTypes = {
56 - title: PropTypes.string,
57 - subtitle: PropTypes.string,
58 - badge: PropTypes.string,
59 - price: PropTypes.string,
60 - discount: PropTypes.string,
61 - episodes: PropTypes.number,
62 - subscribers: PropTypes.number
63 -};
64 -
65 -export default SummerCampCard;
...\ No newline at end of file ...\ No newline at end of file