Browse Source

:construction: add video player demo

Jeremy Zheng 3 năm trước cách đây
mục cha
commit
83af8af4ff

+ 1 - 0
dashboard/package.json

@@ -23,6 +23,7 @@
     "@types/react-copy-to-clipboard": "^5.0.4",
     "@types/react-dom": "^18.0.0",
     "@types/react-pdf": "^5.7.4",
+    "@types/video.js": "^7.3.50",
     "@uiw/react-md-editor": "^3.19.7",
     "antd": "^4.24.2",
     "dayjs": "^1.11.6",

+ 1 - 0
dashboard/src/App.css

@@ -1,5 +1,6 @@
 @import "~antd/dist/antd.min.css";
 @import "~react-quill/dist/quill.snow.css";
+@import "~video.js/dist/video-js.css";
 @import "./assets/font/main.css";
 
 body {

+ 55 - 0
dashboard/src/components/nut/VideoPlayer.tsx

@@ -0,0 +1,55 @@
+import { useRef, useEffect } from "react";
+import videojs from "video.js";
+
+interface IProps {
+  options: videojs.PlayerOptions;
+  onReady: (player: videojs.Player) => void;
+}
+
+const Widget = ({ options, onReady }: IProps) => {
+  const videoRef = useRef<HTMLDivElement>(null);
+  const playerRef = useRef<videojs.Player | null>();
+
+  useEffect(() => {
+    if (!playerRef.current) {
+      const videoElement = document.createElement("video-js");
+
+      videoElement.classList.add("vjs-big-play-centered");
+      if (videoRef.current) {
+        videoRef.current.appendChild(videoElement);
+      }
+
+      const player = (playerRef.current = videojs(videoElement, options, () => {
+        onReady && onReady(player);
+      }));
+    } else {
+      const player = playerRef.current;
+
+      if (options.autoplay !== undefined) {
+        player.autoplay(options.autoplay);
+      }
+      if (options.sources !== undefined) {
+        player.src(options.sources);
+      }
+    }
+  }, [options, playerRef, videoRef, onReady]);
+
+  useEffect(() => {
+    const player = playerRef.current;
+
+    return () => {
+      if (player && !player.isDisposed()) {
+        player.dispose();
+        playerRef.current = null;
+      }
+    };
+  }, [playerRef]);
+
+  return (
+    <div data-vjs-player>
+      <div ref={videoRef} className="video-js" />
+    </div>
+  );
+};
+
+export default Widget;

+ 53 - 2
dashboard/src/pages/nut/index.tsx

@@ -1,13 +1,59 @@
-import { useState } from "react";
-import { Tag, Space, Button } from "antd";
+import { useState, useRef } from "react";
+import { Tag, Row, Col, Space, Button } from "antd";
 import lodash from "lodash";
 import { marked } from "marked";
+import videojs from "video.js";
 
 import FooterBar from "../../components/library/FooterBar";
 
 import HeadBar from "../../components/library/HeadBar";
 import Home from "../../components/nut/Home";
 import InnerDrawer from "../../components/nut/InnerDrawer";
+import VideoPlayer from "../../components/nut/VideoPlayer";
+
+// ------------------------------------------
+
+const VideoBox = () => {
+  const playerRef = useRef<videojs.Player>();
+
+  const handlePlayerReady = (player: videojs.Player) => {
+    if (playerRef.current) {
+      playerRef.current = player;
+      player.on("waiting", () => {
+        console.log("player is waiting");
+      });
+
+      player.on("dispose", () => {
+        console.log("player will dispose");
+      });
+    }
+  };
+
+  return (
+    <VideoPlayer
+      options={{
+        autoplay: true,
+        controls: true,
+        responsive: true,
+        fluid: true,
+        poster: "https://vjs.zencdn.net/v/oceans.png",
+        sources: [
+          {
+            src: "https://vjs.zencdn.net/v/oceans.mp4",
+            type: "video/mp4",
+          },
+          {
+            src: "https://vjs.zencdn.net/v/oceans.webm",
+            type: "video/webm",
+          },
+          { src: "https://vjs.zencdn.net/v/oceans.ogv", type: "video/ogg" },
+        ],
+      }}
+      onReady={handlePlayerReady}
+    />
+  );
+};
+// ------------------------------------------
 
 interface IRandomPanel {
   v1: string;
@@ -42,6 +88,11 @@ const Widget = () => {
         }}
       ></div>
       <div>Home Page</div>
+      <Row>
+        <Col offset={1}>
+          <VideoBox />
+        </Col>
+      </Row>
       <InnerDrawer />
       <div>
         <h1>Mermaid</h1>