diff --git a/apps/web-main/package.json b/apps/web-main/package.json index d4bd610..30fc5d8 100644 --- a/apps/web-main/package.json +++ b/apps/web-main/package.json @@ -17,7 +17,8 @@ "@ricons/fluent": "0.12.0", "@ricons/utils": "0.1.6", "dayjs": "1.11.7", - "identicon": "3.1.1" + "identicon": "3.1.1", + "react-perfect-scrollbar": "1.5.8" }, "devDependencies": { "@types/react": "^18.0.27", diff --git a/apps/web-main/src/view/CourseDetail/components/Material/index.tsx b/apps/web-main/src/view/CourseDetail/components/Material/index.tsx new file mode 100644 index 0000000..917bc71 --- /dev/null +++ b/apps/web-main/src/view/CourseDetail/components/Material/index.tsx @@ -0,0 +1,5 @@ +function Material() { + return
1
; +} + +export default Material; diff --git a/apps/web-main/src/components/Player/index.less b/apps/web-main/src/view/CourseDetail/components/Player/index.less similarity index 73% rename from apps/web-main/src/components/Player/index.less rename to apps/web-main/src/view/CourseDetail/components/Player/index.less index dcfce71..c4d1731 100644 --- a/apps/web-main/src/components/Player/index.less +++ b/apps/web-main/src/view/CourseDetail/components/Player/index.less @@ -37,18 +37,18 @@ } // 圆角 -.vjs-poster, -.video-js { - border-radius: 10px !important; - video { - border-radius: 10px !important; - } -} +// .vjs-poster, +// .video-js { +// border-radius: 10px !important; +// video { +// border-radius: 10px !important; +// } +// } -.video-js { - // box-shadow: 0 0 100px #c8c8c8 !important; -} +// .video-js { +// // box-shadow: 0 0 100px #c8c8c8 !important; +// } -.vjs-control-bar { - border-radius: 0 0 10px 10px !important; -} +// .vjs-control-bar { +// border-radius: 0 0 10px 10px !important; +// } diff --git a/apps/web-main/src/components/Player/index.tsx b/apps/web-main/src/view/CourseDetail/components/Player/index.tsx similarity index 91% rename from apps/web-main/src/components/Player/index.tsx rename to apps/web-main/src/view/CourseDetail/components/Player/index.tsx index 26c8417..9ec72ca 100644 --- a/apps/web-main/src/components/Player/index.tsx +++ b/apps/web-main/src/view/CourseDetail/components/Player/index.tsx @@ -1,5 +1,5 @@ import { useEffect, useRef, useState } from "react"; -import { useScript } from "../../hook"; +import { useScript } from "../../../../hook"; import "./index.less"; export interface IVideo { @@ -35,8 +35,9 @@ function Player(props: IProps) { if (libReady) { const TCPlayer = (window as any).TCPlayer; playerRef.current = TCPlayer("player", { - fileID: "243791579995468466", - appID: "1500018521", + // fileID: "243791579995468466", + // appID: "1500018521", + ...props.video, plugins: { ContinuePlay: { auto: true, diff --git a/apps/web-main/src/view/CourseDetail/index.less b/apps/web-main/src/view/CourseDetail/index.less index cd85924..6c0e555 100644 --- a/apps/web-main/src/view/CourseDetail/index.less +++ b/apps/web-main/src/view/CourseDetail/index.less @@ -1,25 +1,8 @@ .course-detail { padding-top: 60px; - article { - padding: 20px 40px 0 0; - .player-container { - position: relative; - height: 360px; - &.float { - position: fixed !important; - left: 0; - top: 60px; - bottom: 0; - height: auto !important; - right: calc((100% - 1120px) / 2); - z-index: 20; - } - } - } - aside { - padding-left: 20px; + padding: 20px; > h2 { margin-bottom: 10px; } @@ -31,8 +14,17 @@ } .level-2 { display: grid; + padding-left: 10px; + line-height: 30px; grid-template-columns: 9fr 1fr; color: var(--color-text-2); + cursor: pointer; + &:hover { + color: var(--color-text-1); + } + &.active { + color: rgb(var(--primary-4)); + } .time { color: var(--color-text-4); text-align: right; @@ -40,4 +32,38 @@ } } } + + article { + position: relative; + height: 100%; + .mask { + position: absolute; + left: 0; + right: 0; + bottom: 0; + top: 0; + z-index: 30; + background: rgba(255, 255, 255, 1); + display: flex; + justify-content: center; + align-items: center; + } + > main { + height: 100%; + .player-container { + height: 100%; + position: relative; + overflow: hidden; + &.float { + position: fixed !important; + left: 0; + top: 60px; + bottom: 0; + height: auto !important; + right: calc((100% - 1120px) / 2); + z-index: 20; + } + } + } + } } diff --git a/apps/web-main/src/view/CourseDetail/index.tsx b/apps/web-main/src/view/CourseDetail/index.tsx index a737656..1dff2d4 100644 --- a/apps/web-main/src/view/CourseDetail/index.tsx +++ b/apps/web-main/src/view/CourseDetail/index.tsx @@ -1,8 +1,12 @@ -import { useState } from "react"; -import Player, { IVideo } from "../../components/Player"; +import { useEffect, useState } from "react"; import "./index.less"; -import { ResizeBox, Space, Result, Button } from "@arco-design/web-react"; +import { ResizeBox, Space, Result, Button, Spin } from "@arco-design/web-react"; import { Icon } from "@ricons/utils"; +import "react-perfect-scrollbar/dist/css/styles.css"; +import PerfectScrollbar from "react-perfect-scrollbar"; +import Player, { IVideo } from "./components/Player"; +import Material from "./components/Material"; +import { useMount } from "../../hook"; function CourseDetail() { const [toc, setToc] = useState([ @@ -10,25 +14,25 @@ function CourseDetail() { title: "准备", level: 1, }, + { + title: "资料下载", + level: 2, + active: false, + view: , + }, { title: "学习 html, css, javascript 前的准备", level: 2, time: "3:23", - get: false, - video: { - fileID: "243791579995468466", - appID: "1500018521", - }, + active: false, + video: { fileID: "243791579995468466", appID: "1500018521" }, }, { - title: "css 样式的写法", + title: "Vite + React + TS - Google Chrome 2023-02-15 09-55-08", level: 2, time: "4:13", - get: false, - video: { - fileID: "243791580097740418", - appID: "1500018521", - }, + active: false, + video: { fileID: "243791580097740418", appID: "1500018521" }, }, { title: "使用CSS", @@ -38,167 +42,106 @@ function CourseDetail() { title: "使用 css:行内样式", level: 2, time: "5:55", - get: false, + active: false, }, { title: "使用 css:行内样式2", level: 2, time: "6:55", - get: false, - }, - { - title: "使用CSS", - level: 1, - }, - { - title: "使用 css:行内样式", - level: 2, - time: "5:55", - get: false, - }, - { - title: "使用 css:行内样式2", - level: 2, - time: "6:55", - get: false, - }, - { - title: "使用CSS", - level: 1, - }, - { - title: "使用 css:行内样式", - level: 2, - time: "5:55", - get: false, - }, - { - title: "使用 css:行内样式2", - level: 2, - time: "6:55", - get: false, - }, - { - title: "使用CSS", - level: 1, - }, - { - title: "使用 css:行内样式", - level: 2, - time: "5:55", - get: false, - }, - { - title: "使用 css:行内样式2", - level: 2, - time: "6:55", - get: false, - }, - { - title: "使用CSS", - level: 1, - }, - { - title: "使用 css:行内样式", - level: 2, - time: "5:55", - get: false, - }, - { - title: "使用 css:行内样式2", - level: 2, - time: "6:55", - get: false, - }, - { - title: "使用CSS", - level: 1, - }, - { - title: "使用 css:行内样式", - level: 2, - time: "5:55", - get: false, - }, - { - title: "使用 css:行内样式2", - level: 2, - time: "6:55", - get: false, - }, - { - title: "使用CSS", - level: 1, - }, - { - title: "使用 css:行内样式", - level: 2, - time: "5:55", - get: false, - }, - { - title: "使用 css:行内样式2", - level: 2, - time: "6:55", - get: false, + active: false, }, ]); + const [spinVisible, setSpinVisible] = useState(false); const [video, setVideo] = useState(null); + const [view, setView] = useState(null); + const notFound = ( + 1} + > + ); + + useMount(() => { + const first = toc.find((t) => t.level === 2) as any; + setToc((p: any) => + p.map((i: any) => ({ ...i, active: i.title === first.title })) + ); + setView(first?.view); + }); const onclickItem = (i: any) => { - setVideo(i.video); + setToc((t: any) => + t.map((p: any) => ({ ...p, active: i.title === p.title })) + ); + if (i.video) { + setVideo(i.video); + setView(null); + } else { + setView(i.view ?? notFound); + } }; return ( -
+
+ + ,
- 上舰} - > - {/*
- -
*/} + {spinVisible ? ( +
+ +
+ ) : ( +
+ {view} + {/* 默认隐藏播放器 */} +
+ +
+
+ )}
, - , ]} />
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 46f2902..098817e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -189,6 +189,7 @@ importers: less: ^4.1.3 react: ^18.2.0 react-dom: ^18.2.0 + react-perfect-scrollbar: 1.5.8 react-router-dom: 6.8.0 typescript: ^4.9.3 vite: ^4.1.0 @@ -202,6 +203,7 @@ importers: less: registry.npmmirror.com/less/4.1.3 react: registry.npmmirror.com/react/18.2.0 react-dom: registry.npmmirror.com/react-dom/18.2.0_react@18.2.0 + react-perfect-scrollbar: registry.npmmirror.com/react-perfect-scrollbar/1.5.8_biqbaboplfbrettd7655fr4n2y react-router-dom: registry.npmmirror.com/react-router-dom/6.8.0_biqbaboplfbrettd7655fr4n2y devDependencies: '@types/react': registry.npmmirror.com/@types/react/18.0.27 @@ -9831,6 +9833,12 @@ packages: engines: {node: '>=8'} dev: true + registry.npmmirror.com/perfect-scrollbar/1.5.5: + resolution: {integrity: sha512-dzalfutyP3e/FOpdlhVryN4AJ5XDVauVWxybSkLZmakFE2sS3y3pc4JnSprw8tGmHvkaG5Edr5T7LBTZ+WWU2g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/perfect-scrollbar/-/perfect-scrollbar-1.5.5.tgz} + name: perfect-scrollbar + version: 1.5.5 + dev: false + registry.npmmirror.com/performance-now/2.1.0: resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/performance-now/-/performance-now-2.1.0.tgz} name: performance-now @@ -11302,6 +11310,21 @@ packages: version: 16.13.1 dev: false + registry.npmmirror.com/react-perfect-scrollbar/1.5.8_biqbaboplfbrettd7655fr4n2y: + resolution: {integrity: sha512-bQ46m70gp/HJtiBOF3gRzBISSZn8FFGNxznTdmTG8AAwpxG1bJCyn7shrgjEvGSQ5FJEafVEiosY+ccER11OSA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/react-perfect-scrollbar/-/react-perfect-scrollbar-1.5.8.tgz} + id: registry.npmmirror.com/react-perfect-scrollbar/1.5.8 + name: react-perfect-scrollbar + version: 1.5.8 + peerDependencies: + react: '>=16.3.3' + react-dom: '>=16.3.3' + dependencies: + perfect-scrollbar: registry.npmmirror.com/perfect-scrollbar/1.5.5 + prop-types: registry.npmmirror.com/prop-types/15.8.1 + react: registry.npmmirror.com/react/18.2.0 + react-dom: registry.npmmirror.com/react-dom/18.2.0_react@18.2.0 + dev: false + registry.npmmirror.com/react-refresh/0.14.0: resolution: {integrity: sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/react-refresh/-/react-refresh-0.14.0.tgz} name: react-refresh