2023-02-27 15:41:19 +08:00
|
|
|
import "./index.less";
|
2023-02-28 23:33:16 +08:00
|
|
|
import {
|
|
|
|
Select,
|
|
|
|
Message,
|
|
|
|
Space,
|
|
|
|
Tooltip,
|
|
|
|
Dropdown,
|
|
|
|
Button,
|
|
|
|
Menu,
|
|
|
|
} from "@arco-design/web-react";
|
2023-02-27 18:01:37 +08:00
|
|
|
import BsCard from "../../components/Card";
|
2023-03-01 11:18:24 +08:00
|
|
|
import Timeline, { IOnScrollParam } from "./components/Timeline";
|
2023-02-28 17:58:30 +08:00
|
|
|
import Tab20Regular from "@ricons/fluent/Tab20Regular";
|
|
|
|
import Table20Regular from "@ricons/fluent/Table20Regular";
|
2023-02-28 23:33:16 +08:00
|
|
|
import Filter20Regular from "@ricons/fluent/Filter20Regular";
|
2023-03-01 15:24:27 +08:00
|
|
|
import { useEffect, useRef, useState } from "react";
|
2023-03-01 11:18:24 +08:00
|
|
|
import { courseTimeListDefault } from "./mock";
|
2023-02-28 23:33:16 +08:00
|
|
|
import { Icon } from "@ricons/utils";
|
2023-03-01 15:24:27 +08:00
|
|
|
import { useNavigate } from "react-router-dom";
|
2023-02-27 15:41:19 +08:00
|
|
|
|
|
|
|
export default function Index() {
|
2023-03-01 15:24:27 +08:00
|
|
|
const navigate = useNavigate();
|
2023-03-01 11:18:24 +08:00
|
|
|
const thumbnailRef = useRef<HTMLElement | null>(null);
|
|
|
|
const scale = useRef<number>(1); // thumbnail / timeline 高度比例
|
|
|
|
const [timeline, setTimeline] = useState({
|
2023-02-28 23:58:50 +08:00
|
|
|
top: -4,
|
|
|
|
});
|
2023-02-28 23:33:16 +08:00
|
|
|
|
|
|
|
const dropList = (
|
|
|
|
<Menu>
|
2023-03-01 11:18:24 +08:00
|
|
|
<Menu.Item key="asec">升序</Menu.Item>
|
|
|
|
<Menu.Item key="desc">降序</Menu.Item>
|
2023-02-28 23:33:16 +08:00
|
|
|
</Menu>
|
|
|
|
);
|
2023-02-27 15:41:19 +08:00
|
|
|
|
2023-02-28 17:58:30 +08:00
|
|
|
const [actions, setActions] = useState([
|
|
|
|
{
|
|
|
|
key: "tab",
|
2023-02-28 23:33:16 +08:00
|
|
|
icon: <Tab20Regular />,
|
2023-02-28 17:58:30 +08:00
|
|
|
active: false,
|
2023-03-01 11:18:24 +08:00
|
|
|
tip: "使用大缩略图显示单个项目",
|
|
|
|
gridClass: "tab",
|
2023-02-28 17:58:30 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
key: "table",
|
2023-02-28 23:33:16 +08:00
|
|
|
icon: <Table20Regular />,
|
2023-02-28 17:58:30 +08:00
|
|
|
active: true,
|
2023-03-01 11:18:24 +08:00
|
|
|
tip: "列出更多项目",
|
|
|
|
gridClass: "table",
|
2023-02-28 17:58:30 +08:00
|
|
|
},
|
|
|
|
]);
|
|
|
|
|
|
|
|
const [courseTimeList, setCourseTimeList] = useState(courseTimeListDefault);
|
|
|
|
|
|
|
|
const onClickActionItem = (action: any) => {
|
|
|
|
setActions((p) => p.map((a) => ({ ...a, active: a.key === action.key })));
|
|
|
|
};
|
|
|
|
|
2023-03-01 11:18:24 +08:00
|
|
|
/**
|
|
|
|
* 右侧时间线滚动
|
|
|
|
*/
|
|
|
|
const onTimelineScroll = (p: IOnScrollParam) => {
|
2023-02-28 23:33:16 +08:00
|
|
|
const { top, height } = p;
|
|
|
|
//左侧区域高度
|
2023-03-01 11:18:24 +08:00
|
|
|
const { scrollHeight, clientHeight } = thumbnailRef.current!;
|
|
|
|
scale.current = (scrollHeight - clientHeight) / height;
|
|
|
|
thumbnailRef.current!.scrollTop = top * scale.current;
|
2023-02-28 23:58:50 +08:00
|
|
|
};
|
|
|
|
|
2023-03-01 11:18:24 +08:00
|
|
|
/**
|
|
|
|
* 左侧缩略图预览区域滚动
|
|
|
|
*/
|
|
|
|
const onThumbnailScroll = () => {
|
|
|
|
const { scrollHeight, scrollTop } = thumbnailRef.current!;
|
2023-02-28 23:58:50 +08:00
|
|
|
const isTop = scrollTop === 0;
|
|
|
|
const isBottom = scrollTop === scrollHeight;
|
2023-03-01 11:18:24 +08:00
|
|
|
const top = isTop ? -4 : scrollTop / scale.current; // 修正顶部
|
|
|
|
setTimeline({ top });
|
2023-02-28 23:33:16 +08:00
|
|
|
};
|
|
|
|
|
2023-03-01 15:24:27 +08:00
|
|
|
const onClickCourseItem = (d: any) => {
|
|
|
|
navigate(`/course/detail/${d.id}`);
|
|
|
|
};
|
|
|
|
|
2023-02-27 15:41:19 +08:00
|
|
|
return (
|
|
|
|
<div className="container course">
|
2023-02-28 17:58:30 +08:00
|
|
|
<div className="action-bar">
|
2023-03-01 11:18:24 +08:00
|
|
|
<Space>
|
|
|
|
{actions.map((action) => (
|
|
|
|
<Tooltip key={action.key} content={action.tip}>
|
2023-02-28 23:33:16 +08:00
|
|
|
<Button
|
|
|
|
type="text"
|
2023-03-01 11:18:24 +08:00
|
|
|
onClick={() => onClickActionItem(action)}
|
2023-02-28 23:33:16 +08:00
|
|
|
icon={
|
2023-03-01 11:18:24 +08:00
|
|
|
<Icon
|
|
|
|
size={20}
|
|
|
|
color={
|
|
|
|
action.active
|
|
|
|
? "rgb(var(--primary-6))"
|
|
|
|
: "var(--color-text-2)"
|
|
|
|
}
|
|
|
|
>
|
|
|
|
{action.icon}
|
2023-02-28 23:33:16 +08:00
|
|
|
</Icon>
|
|
|
|
}
|
|
|
|
/>
|
2023-03-01 11:18:24 +08:00
|
|
|
</Tooltip>
|
|
|
|
))}
|
|
|
|
<Dropdown droplist={dropList} position="bl">
|
|
|
|
<Button
|
|
|
|
type="text"
|
|
|
|
icon={
|
|
|
|
<Icon size={20} color="var(--color-text-2)">
|
|
|
|
<Filter20Regular />
|
|
|
|
</Icon>
|
|
|
|
}
|
|
|
|
/>
|
|
|
|
</Dropdown>
|
|
|
|
</Space>
|
2023-02-28 17:58:30 +08:00
|
|
|
</div>
|
2023-03-01 11:18:24 +08:00
|
|
|
<div className="thumbnail-timeline">
|
|
|
|
<div className="thumbnail-container">
|
|
|
|
<article ref={thumbnailRef} onScroll={onThumbnailScroll}>
|
2023-02-28 23:33:16 +08:00
|
|
|
{courseTimeList.map((item, index) => (
|
|
|
|
<section key={index}>
|
|
|
|
<div className="time">
|
|
|
|
{item.year}年{item.month}月
|
|
|
|
</div>
|
|
|
|
<div className="statistic">{item.data.length} 个视频</div>
|
2023-03-01 11:18:24 +08:00
|
|
|
<div
|
|
|
|
className={`grid ${actions.find((a) => a.active)?.gridClass}`}
|
|
|
|
>
|
2023-02-28 23:33:16 +08:00
|
|
|
{item.data.map((d: any) => (
|
2023-03-01 15:24:27 +08:00
|
|
|
<BsCard
|
|
|
|
onClick={() => onClickCourseItem(d)}
|
|
|
|
key={d.id}
|
|
|
|
imgUrl={d.img}
|
|
|
|
title={d.title}
|
|
|
|
/>
|
2023-02-28 23:33:16 +08:00
|
|
|
))}
|
|
|
|
</div>
|
|
|
|
</section>
|
|
|
|
))}
|
|
|
|
</article>
|
2023-02-28 17:58:30 +08:00
|
|
|
</div>
|
2023-03-01 11:18:24 +08:00
|
|
|
<Timeline
|
|
|
|
className="timeline-container"
|
2023-02-28 23:33:16 +08:00
|
|
|
data={courseTimeList}
|
2023-03-01 11:18:24 +08:00
|
|
|
onScroll={onTimelineScroll}
|
|
|
|
model={{ top: timeline.top }}
|
2023-02-28 23:33:16 +08:00
|
|
|
/>
|
2023-02-27 18:01:37 +08:00
|
|
|
</div>
|
2023-02-27 15:41:19 +08:00
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|