rht02252015
This commit is contained in:
parent
4eebb49c7f
commit
e795d2345f
|
@ -58,7 +58,7 @@ export default function CourseList({
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
{courses.length > 0 ? (
|
{courses.length > 0 ? (
|
||||||
<>
|
<>
|
||||||
<div className={`grid grid-cols-${cols} gap-6`}>
|
<div className={`grid lg:grid-cols-${cols} gap-6`}>
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<Skeleton paragraph={{ rows: 5 }}></Skeleton>
|
<Skeleton paragraph={{ rows: 5 }}></Skeleton>
|
||||||
) : (
|
) : (
|
||||||
|
|
|
@ -1,18 +1,13 @@
|
||||||
import React, { useState, useCallback, useEffect, useMemo } from "react";
|
import React, { useState, useCallback, useEffect, useMemo } from "react";
|
||||||
import { Typography, Button, Spin } from "antd";
|
import { Typography, Button, Spin, Skeleton } from "antd";
|
||||||
import { stringToColor, TaxonomySlug, TermDto } from "@nice/common";
|
import { stringToColor, TaxonomySlug, TermDto } from "@nice/common";
|
||||||
import { api } from "@nice/client";
|
import { api } from "@nice/client";
|
||||||
import { ControlOutlined } from "@ant-design/icons";
|
import { ControlOutlined } from "@ant-design/icons";
|
||||||
import { useNavigate, useSearchParams } from "react-router-dom";
|
import { useNavigate, useSearchParams } from "react-router-dom";
|
||||||
|
import LookForMore from "./LookForMore";
|
||||||
|
import CategorySectionCard from "./CategorySectionCard";
|
||||||
|
|
||||||
const { Title, Text } = Typography;
|
const { Title, Text } = Typography;
|
||||||
|
|
||||||
interface CourseCategory {
|
|
||||||
name: string;
|
|
||||||
count: number;
|
|
||||||
description: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const CategorySection = () => {
|
const CategorySection = () => {
|
||||||
const [hoveredIndex, setHoveredIndex] = useState<number | null>(null);
|
const [hoveredIndex, setHoveredIndex] = useState<number | null>(null);
|
||||||
const [showAll, setShowAll] = useState(false);
|
const [showAll, setShowAll] = useState(false);
|
||||||
|
@ -39,9 +34,6 @@ const CategorySection = () => {
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log(courseCategoriesData);
|
|
||||||
// 如果 showAll 为 true,则显示所有分类数据,
|
|
||||||
// 如果 showAll 为 false,则只显示前 8 个分类数据,
|
|
||||||
if (!isLoading) {
|
if (!isLoading) {
|
||||||
if (showAll) {
|
if (showAll) {
|
||||||
setDisplayedCategories(courseCategoriesData);
|
setDisplayedCategories(courseCategoriesData);
|
||||||
|
@ -50,13 +42,6 @@ const CategorySection = () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [courseCategoriesData, showAll]);
|
}, [courseCategoriesData, showAll]);
|
||||||
// const courseCategories: CourseCategory[] = useMemo(() => {
|
|
||||||
// return data?.map((term) => ({
|
|
||||||
// name: term.name,
|
|
||||||
// count: term.hasChildren ? term.children.length : 0,
|
|
||||||
// description: term.description
|
|
||||||
// })) || [];
|
|
||||||
// },[data])
|
|
||||||
const handleMouseEnter = useCallback((index: number) => {
|
const handleMouseEnter = useCallback((index: number) => {
|
||||||
setHoveredIndex(index);
|
setHoveredIndex(index);
|
||||||
}, []);
|
}, []);
|
||||||
|
@ -82,106 +67,27 @@ const CategorySection = () => {
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<Spin></Spin>
|
<Skeleton></Skeleton>
|
||||||
) : (
|
) : (
|
||||||
displayedCategories.map((category, index) => {
|
displayedCategories.map((category, index) => {
|
||||||
const categoryColor = stringToColor(category.name);
|
const categoryColor = stringToColor(category.name);
|
||||||
const isHovered = hoveredIndex === index;
|
const isHovered = hoveredIndex === index;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<CategorySectionCard
|
||||||
key={index}
|
key={index}
|
||||||
className="group relative min-h-[130px] rounded-2xl transition-all duration-700 ease-out cursor-pointer will-change-transform hover:-translate-y-2"
|
index={index}
|
||||||
onMouseEnter={() => handleMouseEnter(index)}
|
category={category}
|
||||||
onMouseLeave={handleMouseLeave}
|
categoryColor={categoryColor}
|
||||||
role="button"
|
isHovered={isHovered}
|
||||||
tabIndex={0}
|
handleMouseEnter={handleMouseEnter}
|
||||||
aria-label={`查看${category.name}课程类别`}
|
handleMouseLeave={handleMouseLeave}
|
||||||
onClick={() => {
|
/>
|
||||||
console.log(category.name);
|
|
||||||
navigate(
|
|
||||||
`/courses?category=${category.name}`
|
|
||||||
);
|
|
||||||
window.scrollTo({
|
|
||||||
top: 0,
|
|
||||||
behavior: "smooth",
|
|
||||||
});
|
|
||||||
}}>
|
|
||||||
<div className="absolute -inset-0.5 bg-gradient-to-r from-gray-200 to-gray-300 opacity-50 rounded-2xl transition-all duration-700 group-hover:opacity-75" />
|
|
||||||
<div
|
|
||||||
className={`absolute inset-0 rounded-2xl bg-gradient-to-br from-white to-gray-50 shadow-lg transition-all duration-700 ease-out ${
|
|
||||||
isHovered
|
|
||||||
? "scale-[1.02] bg-opacity-95"
|
|
||||||
: "scale-100 bg-opacity-90"
|
|
||||||
}`}
|
|
||||||
/>
|
|
||||||
<div
|
|
||||||
className={`absolute inset-0 rounded-2xl transition-all duration-700 ease-out ${
|
|
||||||
isHovered
|
|
||||||
? "shadow-[0_8px_30px_rgb(0,0,0,0.12)]"
|
|
||||||
: "shadow-none opacity-0"
|
|
||||||
}`}
|
|
||||||
/>
|
|
||||||
<div
|
|
||||||
className={`absolute top-0 left-1/2 -translate-x-1/2 h-1 rounded-full transition-all duration-500 ease-out `}
|
|
||||||
style={{
|
|
||||||
backgroundColor: categoryColor,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<div className="relative w-full h-full p-6">
|
|
||||||
<div className="flex w-2/3 absolute left-1/2 -translate-x-1/2 top-1/2 -translate-y-1/2 flex-col space-y-4 mb-4">
|
|
||||||
<Text
|
|
||||||
strong
|
|
||||||
className="text-xl font-medium tracking-wide">
|
|
||||||
{category.name}
|
|
||||||
</Text>
|
|
||||||
{/* <span
|
|
||||||
className={`px-3 py-1 rounded-full text-sm w-fit font-medium transition-all duration-500 ease-out ${
|
|
||||||
isHovered ? 'shadow-md scale-105' : ''
|
|
||||||
}`}
|
|
||||||
style={{
|
|
||||||
backgroundColor: `${categoryColor}15`,
|
|
||||||
color: categoryColor
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{category.children.length} 门课程
|
|
||||||
</span> */}
|
|
||||||
</div>
|
|
||||||
<Text
|
|
||||||
type="secondary"
|
|
||||||
className="block text-sm leading-relaxed opacity-90">
|
|
||||||
{category.description}
|
|
||||||
</Text>
|
|
||||||
<div
|
|
||||||
className={` mt-6 absolute bottom-4 right-6 text-sm font-medium flex items-center space-x-2 transition-all duration-500 ease-out `}
|
|
||||||
style={{ color: categoryColor }}>
|
|
||||||
<span>了解更多</span>
|
|
||||||
<span
|
|
||||||
className={`transform transition-all duration-500 ease-out `}>
|
|
||||||
→
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{!isLoading && (
|
<LookForMore to={"/courses"}></LookForMore>
|
||||||
<div className="flex justify-center mt-12">
|
|
||||||
<Button
|
|
||||||
type="default"
|
|
||||||
size="large"
|
|
||||||
className="px-8 h-12 text-base font-medium hover:shadow-md transition-all duration-300"
|
|
||||||
onClick={() => {
|
|
||||||
//setShowAll(!showAll)
|
|
||||||
navigate("/courses");
|
|
||||||
window.scrollTo({ top: 0, behavior: "smooth" });
|
|
||||||
}}>
|
|
||||||
{showAll ? "收起" : "查看更多分类"}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
|
import { Typography } from "antd";
|
||||||
|
export default function CategorySectionCard({index,handleMouseEnter,handleMouseLeave,category,categoryColor,isHovered,}) {
|
||||||
|
const navigate = useNavigate()
|
||||||
|
const { Title, Text } = Typography;
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
className="group relative min-h-[130px] rounded-2xl transition-all duration-700 ease-out cursor-pointer will-change-transform hover:-translate-y-2"
|
||||||
|
onMouseEnter={() => handleMouseEnter(index)}
|
||||||
|
onMouseLeave={handleMouseLeave}
|
||||||
|
role="button"
|
||||||
|
tabIndex={0}
|
||||||
|
aria-label={`查看${category.name}课程类别`}
|
||||||
|
onClick={() => {
|
||||||
|
console.log(category.name);
|
||||||
|
navigate(
|
||||||
|
`/courses?category=${category.name}`
|
||||||
|
);
|
||||||
|
window.scrollTo({
|
||||||
|
top: 0,
|
||||||
|
behavior: "smooth",
|
||||||
|
});
|
||||||
|
}}>
|
||||||
|
<div className="absolute -inset-0.5 bg-gradient-to-r from-gray-200 to-gray-300 opacity-50 rounded-2xl transition-all duration-700 group-hover:opacity-75" />
|
||||||
|
<div
|
||||||
|
className={`absolute inset-0 rounded-2xl bg-gradient-to-br from-white to-gray-50 shadow-lg transition-all duration-700 ease-out ${isHovered
|
||||||
|
? "scale-[1.02] bg-opacity-95"
|
||||||
|
: "scale-100 bg-opacity-90"
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
className={`absolute inset-0 rounded-2xl transition-all duration-700 ease-out ${isHovered
|
||||||
|
? "shadow-[0_8px_30px_rgb(0,0,0,0.12)]"
|
||||||
|
: "shadow-none opacity-0"
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
className={`absolute w-1/2 top-0 left-1/2 -translate-x-1/2 h-1 rounded-full transition-all duration-500 ease-out `}
|
||||||
|
style={{
|
||||||
|
backgroundColor: categoryColor,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<div className="relative w-full h-full p-6">
|
||||||
|
<div className="flex w-2/3 absolute left-1/2 -translate-x-1/2 top-1/2 -translate-y-1/2 flex-col space-y-4 mb-4">
|
||||||
|
<Text
|
||||||
|
strong
|
||||||
|
className="text-xl font-medium tracking-wide">
|
||||||
|
{category.name}
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={` mt-6 absolute bottom-4 right-6 text-sm font-medium flex items-center space-x-2 transition-all duration-500 ease-out `}
|
||||||
|
style={{ color: categoryColor }}>
|
||||||
|
<span>了解更多</span>
|
||||||
|
<span
|
||||||
|
className={`transform transition-all duration-500 ease-out `}>
|
||||||
|
→
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
|
@ -6,6 +6,7 @@ import { TaxonomySlug, TermDto } from "@nice/common";
|
||||||
import { api } from "@nice/client";
|
import { api } from "@nice/client";
|
||||||
import { CoursesSectionTag } from "./CoursesSectionTag";
|
import { CoursesSectionTag } from "./CoursesSectionTag";
|
||||||
import CourseList from "../../courses/components/CourseList";
|
import CourseList from "../../courses/components/CourseList";
|
||||||
|
import LookForMore from "./LookForMore";
|
||||||
interface GetTaxonomyProps {
|
interface GetTaxonomyProps {
|
||||||
categories: string[];
|
categories: string[];
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
|
@ -97,20 +98,7 @@ const CoursesSection: React.FC<CoursesSectionProps> = ({
|
||||||
}}
|
}}
|
||||||
showPagination={false}
|
showPagination={false}
|
||||||
cols={4}></CourseList>
|
cols={4}></CourseList>
|
||||||
{
|
<LookForMore to={"/courses"}></LookForMore>
|
||||||
<div className="flex items-center gap-4 justify-between mt-12">
|
|
||||||
<div className="h-[1px] flex-grow bg-gradient-to-r from-transparent via-gray-300 to-transparent"></div>
|
|
||||||
<div className="flex justify-end">
|
|
||||||
<Button
|
|
||||||
type="link"
|
|
||||||
onClick={() => navigate("/courses")}
|
|
||||||
className="flex items-center gap-2 text-gray-600 hover:text-blue-600 font-medium transition-colors duration-300">
|
|
||||||
查看更多
|
|
||||||
<ArrowRightOutlined />
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
import { ArrowRightOutlined } from "@ant-design/icons";
|
||||||
|
import { Button } from "antd";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
|
|
||||||
|
export default function LookForMore({to}:{to:string}) {
|
||||||
|
const navigate = useNavigate();
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="flex items-center gap-4 justify-between mt-12">
|
||||||
|
<div className="h-[1px] flex-grow bg-gradient-to-r from-transparent via-gray-300 to-transparent"></div>
|
||||||
|
<div className="flex justify-end">
|
||||||
|
<Button
|
||||||
|
type="link"
|
||||||
|
onClick={() => navigate(to)}
|
||||||
|
className="flex items-center gap-2 text-gray-600 hover:text-blue-600 font-medium transition-colors duration-300">
|
||||||
|
查看更多
|
||||||
|
<ArrowRightOutlined />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue