From 8c6921b366f3dea539b5dacd7a182394258c5667 Mon Sep 17 00:00:00 2001 From: cheerchen Date: Thu, 26 Aug 2021 17:53:42 +0800 Subject: [PATCH] feat(whiteboard): support multi window --- .commitlintrc.js | 1 + .github/workflows/deploy-web-dev.yml | 1 + cspell.config.js | 2 + desktop/renderer-app/package.json | 6 +- .../src/components/Whiteboard.less | 37 +-- .../src/components/Whiteboard.tsx | 73 ++--- .../src/pages/CloudStoragePage/index.tsx | 50 +--- .../src/stores/WhiteboardStore.ts | 143 ++++++++- web/flat-web/package.json | 6 +- web/flat-web/src/components/Whiteboard.less | 37 +-- web/flat-web/src/components/Whiteboard.tsx | 73 ++--- .../CloudStoragePage/CloudStoragePanel.tsx | 51 +--- web/flat-web/src/stores/WhiteboardStore.ts | 161 ++++++++++- yarn.lock | 272 ++++++++---------- 14 files changed, 520 insertions(+), 393 deletions(-) diff --git a/.commitlintrc.js b/.commitlintrc.js index 69d49c0eda4..f979956c9f6 100644 --- a/.commitlintrc.js +++ b/.commitlintrc.js @@ -48,6 +48,7 @@ module.exports = { "husky", "lint", "project", + "vscode", ], ], "scope-case": [2, "always", ["lower-case", "kebab-case"]], diff --git a/.github/workflows/deploy-web-dev.yml b/.github/workflows/deploy-web-dev.yml index 139a06586b3..b65eb849b8a 100644 --- a/.github/workflows/deploy-web-dev.yml +++ b/.github/workflows/deploy-web-dev.yml @@ -3,6 +3,7 @@ on: push: branches: - "main" + - "dev" paths: - "web/flat-web/**" - "packages/flat-components/src/**" diff --git a/cspell.config.js b/cspell.config.js index 67d9b721dd5..168bd7d42f6 100644 --- a/cspell.config.js +++ b/cspell.config.js @@ -84,6 +84,8 @@ module.exports = { "pickone", // chance "viewports", // storybook "videojs", // @videojs/vhs-utils + "telebox", // @netless/widnow-manager + "Buildin", // @netless/widnow-manager // misc "npmrc", diff --git a/desktop/renderer-app/package.json b/desktop/renderer-app/package.json index 5250c1329d4..2e31071d946 100644 --- a/desktop/renderer-app/package.json +++ b/desktop/renderer-app/package.json @@ -8,13 +8,11 @@ "@netless/combine-player": "^1.1.4", "@netless/cursor-tool": "^0.1.0", "@netless/fetch-middleware": "^1.0.7", - "@netless/page-controller": "^0.0.4", "@netless/player-controller": "^0.0.9", - "@netless/preview-controller": "^0.0.9", "@netless/redo-undo": "^0.0.5", "@netless/tool-box": "^0.1.4", "@netless/video-js-plugin": "^0.3.6", - "@netless/zoom-controller": "^0.1.1", + "@netless/window-manager": "^0.1.41", "@videojs/vhs-utils": "^2.3.0", "agora-rtm-sdk": "^1.4.3", "antd": "^4.15.4", @@ -43,7 +41,7 @@ "react-virtualized": "^9.22.2", "uuid": "^8.3.2", "video.js": "7.10.2", - "white-web-sdk": "2.13.17" + "white-web-sdk": "2.13.19" }, "devDependencies": { "@netless/eslint-plugin": "1.1.2", diff --git a/desktop/renderer-app/src/components/Whiteboard.less b/desktop/renderer-app/src/components/Whiteboard.less index b67f8a9404f..3b87e75f793 100644 --- a/desktop/renderer-app/src/components/Whiteboard.less +++ b/desktop/renderer-app/src/components/Whiteboard.less @@ -30,13 +30,10 @@ z-index: 3; bottom: 8px; left: 8px; -} -.zoom-controller-box { - position: absolute; - left: 76px; - z-index: 3; - bottom: 8px; + &.is-disabled { + display: none; + } } .page-controller-box { @@ -44,33 +41,9 @@ z-index: 3; bottom: 8px; right: 8px; -} -.page-controller-mid-box { - display: flex; - align-items: center; - justify-content: center; - background-color: white; - height: 32px; - padding-left: 4px; - padding-right: 4px; - border-radius: 4px; - user-select: none; - font-size: 12px; - box-shadow: 0 4px 12px 0 rgba(0, 0, 0, 0.08); -} - -.page-preview-cell { - width: 24px; - height: 24px; - display: flex; - justify-content: center; - align-items: center; - cursor: pointer; - background-color: white; - border-radius: 2px; - &:hover { - background: rgba(33, 35, 36, 0.1); + &.is-disabled { + display: none; } } diff --git a/desktop/renderer-app/src/components/Whiteboard.tsx b/desktop/renderer-app/src/components/Whiteboard.tsx index e84a03dfb1c..3e45812eb70 100644 --- a/desktop/renderer-app/src/components/Whiteboard.tsx +++ b/desktop/renderer-app/src/components/Whiteboard.tsx @@ -1,16 +1,15 @@ -import PageController from "@netless/page-controller"; -import PreviewController from "@netless/preview-controller"; +import "@netless/window-manager/dist/style.css"; +import "./Whiteboard.less"; + import RedoUndo from "@netless/redo-undo"; import ToolBox from "@netless/tool-box"; -import ZoomController from "@netless/zoom-controller"; import classNames from "classnames"; import { observer } from "mobx-react-lite"; import React, { useCallback } from "react"; -import { RoomPhase } from "white-web-sdk"; -import pagesSVG from "../assets/image/pages.svg"; +import { WindowManager } from "@netless/window-manager"; import { WhiteboardStore } from "../stores/WhiteboardStore"; import { isSupportedImageType, onDropImage } from "../utils/dnd/image"; -import "./Whiteboard.less"; +import { ScenesController } from "flat-components"; export interface WhiteboardProps { whiteboardStore: WhiteboardStore; @@ -20,14 +19,22 @@ export const Whiteboard = observer(function Whiteboard({ whiteb const { room } = whiteboardStore; const bindWhiteboard = useCallback( - (ref: HTMLDivElement) => { - if (room) { - room.bindHtmlElement(ref); - if (room.phase === RoomPhase.Connected) { - room.scalePptToFit(); - } + async (ref: HTMLDivElement | null) => { + if (ref && room) { + await WindowManager.mount({ + room, + container: ref, + collectorStyles: { + position: "absolute", + right: "10px", + bottom: "60px", + }, + }); + whiteboardStore.onMainViewModeChange(); + whiteboardStore.onWindowManagerBoxStateChange(); } }, + // eslint-disable-next-line react-hooks/exhaustive-deps [room], ); @@ -66,37 +73,31 @@ export const Whiteboard = observer(function Whiteboard({ whiteb onDragOver={onDragOver} onDrop={onDrop} > -
- -
-
+
-
-
- -
- {"pages"} -
-
+
+
- - {/* */}
diff --git a/desktop/renderer-app/src/pages/CloudStoragePage/index.tsx b/desktop/renderer-app/src/pages/CloudStoragePage/index.tsx index fa55f39594a..48b3ce6f987 100644 --- a/desktop/renderer-app/src/pages/CloudStoragePage/index.tsx +++ b/desktop/renderer-app/src/pages/CloudStoragePage/index.tsx @@ -11,7 +11,7 @@ import { queryConvertingTaskStatus } from "../../apiMiddleware/courseware-conver import { convertFinish } from "../../apiMiddleware/flatServer/storage"; import { useIsomorphicLayoutEffect } from "react-use"; import { MainPageLayoutContainer } from "../../components/MainPageLayoutContainer"; -import { RoomPhase, SceneDefinition } from "white-web-sdk"; +import { SceneDefinition } from "white-web-sdk"; import { useTranslation } from "react-i18next"; import { RequestErrorCode } from "../../constants/ErrorCode"; import { ServerRequestError } from "../../utils/error/ServerRequestError"; @@ -63,12 +63,9 @@ export const CloudStoragePage = observer(function CloudSt await insertImage(file); break; } - case ".mp3": { - insertAudio(file); - break; - } + case ".mp3": case ".mp4": { - insertVideo(file); + insertMediaFile(file); break; } case ".doc": @@ -92,6 +89,8 @@ export const CloudStoragePage = observer(function CloudSt } async function insertImage(file: CloudStorageFile): Promise { + await whiteboard?.switchMainViewToWriter(); + const room = whiteboard?.room; if (!room) { return; @@ -132,34 +131,8 @@ export const CloudStoragePage = observer(function CloudSt room.completeImageUpload(uuid, file.fileURL); } - function insertAudio(file: CloudStorageFile): void { - const room = whiteboard?.room; - if (!room) { - return; - } - - room.insertPlugin("video.js", { - originX: -240, - originY: -43, - width: 480, - height: 86, - attributes: { src: file.fileURL }, - }); - } - - function insertVideo(file: CloudStorageFile): void { - const room = whiteboard?.room; - if (!room) { - return; - } - - room.insertPlugin("video.js", { - originX: -240, - originY: -135, - width: 480, - height: 270, - attributes: { src: file.fileURL }, - }); + function insertMediaFile(file: CloudStorageFile): void { + whiteboard?.openMediaFileInWindowManager(file.fileURL, file.fileName); } async function insertDocs(file: CloudStorageFile, ext: string): Promise { @@ -208,19 +181,16 @@ export const CloudStoragePage = observer(function CloudSt f => ({ name: v4uuid(), ppt: { + src: f.conversionFileUrl, width: f.width, height: f.height, - src: f.conversionFileUrl, previewURL: f.preview, }, }), ); const uuid = v4uuid(); - room.putScenes(`/${taskUUID}/${uuid}`, scenes); - room.setScenePath(`/${taskUUID}/${uuid}/${scenes[0].name}`); - if (room.phase === RoomPhase.Connected) { - room.scalePptToFit(); - } + const scenesPath = `/${taskUUID}/${uuid}`; + whiteboard?.openDocsFileInWindowManager(scenesPath, file.fileName, scenes); } else { void message.error(t("unable-to-insert-courseware")); } diff --git a/desktop/renderer-app/src/stores/WhiteboardStore.ts b/desktop/renderer-app/src/stores/WhiteboardStore.ts index 5738b72dc07..35c0924c4a2 100644 --- a/desktop/renderer-app/src/stores/WhiteboardStore.ts +++ b/desktop/renderer-app/src/stores/WhiteboardStore.ts @@ -1,5 +1,6 @@ import "video.js/dist/video-js.css"; +import { BuiltinApps, WindowManager } from "@netless/window-manager"; import { makeAutoObservable, observable, runInAction } from "mobx"; import { createPlugins, @@ -8,7 +9,9 @@ import { Room, RoomPhase, RoomState, + SceneDefinition, ViewMode, + ViewVisionMode, WhiteWebSdk, } from "white-web-sdk"; import { @@ -27,10 +30,15 @@ export class WhiteboardStore { public room: Room | null = null; public phase: RoomPhase = RoomPhase.Connecting; public viewMode: ViewMode | null = null; + public windowManager: WindowManager | null = null; public isWritable: boolean; public isShowPreviewPanel = false; public isFileOpen = false; public isKicked = false; + public isFocusWindow = false; + public isWindowMaximization = false; + public currentSceneIndex = 0; + public scenesCount = 0; /** is room Creator */ public readonly isCreator: boolean; @@ -71,6 +79,26 @@ export class WhiteboardStore { } }; + public updateWindowManager = (windowManager: WindowManager): void => { + this.windowManager = windowManager; + }; + + public updateCurrentSceneIndex = (currentSceneIndex: number): void => { + this.currentSceneIndex = currentSceneIndex; + }; + + public updateScenesCount = (scenesCount: number): void => { + this.scenesCount = scenesCount; + }; + + public updateWindowMaximization = (isMaximization: boolean): void => { + this.isWindowMaximization = isMaximization; + }; + + public updateFocusWindowManager = (isFocus: boolean): void => { + this.isFocusWindow = isFocus; + }; + public setFileOpen = (open: boolean): void => { this.isFileOpen = open; }; @@ -87,10 +115,87 @@ export class WhiteboardStore { this.isShowPreviewPanel = show; }; + public switchMainViewToWriter = async (): Promise => { + if (this.windowManager && this.isFocusWindow) { + await this.windowManager.switchMainViewToWriter(); + } + }; + + public addMainViewScene = (): void => { + if (this.room && this.windowManager) { + const currentScene = this.currentSceneIndex + 1; + const scenePath = this.room.state.sceneState.scenePath; + const pathName = this.scenesPathName(scenePath); + + this.room.putScenes(pathName, [{}], currentScene); + this.windowManager.setMainViewSceneIndex(this.currentSceneIndex + 1); + } + }; + + public preMainViewScene = (): void => { + if (this.windowManager && this.currentSceneIndex > 0) { + this.windowManager.setMainViewSceneIndex(this.currentSceneIndex - 1); + } + }; + + public nextMainViewScene = (): void => { + if (this.windowManager && this.currentSceneIndex < this.scenesCount - 1) { + this.windowManager.setMainViewSceneIndex(this.currentSceneIndex + 1); + } + }; + private preloadPPTResource = debounce(async (pptSrc: string): Promise => { await getCoursewarePreloader().preload(pptSrc); }, 2000); + public openDocsFileInWindowManager = async ( + scenePath: string, + title: string, + scenes: SceneDefinition[], + ): Promise => { + await this.windowManager?.addApp({ + kind: BuiltinApps.DocsViewer, + options: { + scenePath, + title, + scenes: scenes, + }, + }); + }; + + public openMediaFileInWindowManager = async ( + resourceSrc: string, + title: string, + ): Promise => { + await this.windowManager?.addApp({ + kind: BuiltinApps.MediaPlayer, + options: { + title, + }, + attributes: { + src: resourceSrc, + }, + }); + }; + + public onMainViewModeChange = (): void => { + this.windowManager?.emitter.on("mainViewModeChange", mode => { + const isWindow = mode !== ViewVisionMode.Writable; + this.updateFocusWindowManager(isWindow); + if (!isWindow && this.room) { + this.updateCurrentSceneIndex(this.room.state.sceneState.index); + this.updateScenesCount(this.room.state.sceneState.scenes.length); + } + }); + }; + + public onWindowManagerBoxStateChange = (): void => { + this.windowManager?.emitter.on("boxStateChange", mode => { + const isMaximization = mode === "maximized"; + this.updateWindowMaximization(isMaximization); + }); + }; + public async joinWhiteboardRoom(): Promise { if (!globalStore.userUUID) { throw new Error("Missing userUUID"); @@ -152,6 +257,8 @@ export class WhiteboardStore { changeToArrow: "a", changeToHand: "h", }, + useMultiViews: true, + invisiblePlugins: [WindowManager], }, { onPhaseChanged: phase => { @@ -175,6 +282,14 @@ export class WhiteboardStore { } catch (err) { console.log(err); } + + if ( + this.room && + this.windowManager?.mainView.mode === ViewVisionMode.Writable + ) { + this.updateCurrentSceneIndex(this.room.state.sceneState.index); + this.updateScenesCount(this.room.state.sceneState.scenes.length); + } }, onDisconnectWithError: error => { this.preloadPPTResource.cancel(); @@ -222,19 +337,39 @@ export class WhiteboardStore { this.updateRoom(room); + this.updateCurrentSceneIndex(room.state.sceneState.index); + + this.updateScenesCount(room.state.sceneState.scenes.length); + + if (this.room) { + const windowManager = this.room.getInvisiblePlugin(WindowManager.kind) as WindowManager; + this.updateWindowManager(windowManager); + } + if (NODE_ENV === "development") { (window as any).room = room; + (window as any).manager = this.windowManager; } } public destroy(): void { - if (this.room) { - this.preloadPPTResource.cancel(); - this.room.callbacks.off(); - } + this.preloadPPTResource.cancel(); + this.windowManager?.destroy(); + this.room?.callbacks.off(); + if (NODE_ENV === "development") { (window as any).room = null; + (window as any).manager = null; } console.log(`Whiteboard unloaded: ${globalStore.whiteboardRoomUUID}`); } + + private scenesPathName = (scenePath: string): string => { + const cells = scenePath.split("/"); + const popCell = cells.pop(); + if (popCell === "") { + cells.pop(); + } + return cells.join("/"); + }; } diff --git a/web/flat-web/package.json b/web/flat-web/package.json index 1f341d97286..9729d351b69 100644 --- a/web/flat-web/package.json +++ b/web/flat-web/package.json @@ -36,13 +36,11 @@ "@loadable/component": "^5.15.0", "@netless/combine-player": "^1.1.6", "@netless/cursor-tool": "^0.1.0", - "@netless/page-controller": "^0.0.4", "@netless/player-controller": "^0.0.9", - "@netless/preview-controller": "^0.0.9", "@netless/redo-undo": "^0.0.5", "@netless/tool-box": "^0.1.5", "@netless/video-js-plugin": "^0.3.6", - "@netless/zoom-controller": "^0.1.1", + "@netless/window-manager": "^0.1.41", "@videojs/vhs-utils": "^2.3.0", "@zip.js/zip.js": "^2.3.7", "agora-rtc-sdk-ng": "^4.5.0", @@ -73,7 +71,7 @@ "react-virtualized": "^9.22.2", "uuid": "^8.3.2", "video.js": "7.10.2", - "white-web-sdk": "2.13.17" + "white-web-sdk": "2.13.19" }, "scripts": { "postinstall": "esbuild-dev ./scripts/post-install.ts", diff --git a/web/flat-web/src/components/Whiteboard.less b/web/flat-web/src/components/Whiteboard.less index 11fbf83d7b9..ee6818cb0dc 100644 --- a/web/flat-web/src/components/Whiteboard.less +++ b/web/flat-web/src/components/Whiteboard.less @@ -29,13 +29,10 @@ z-index: 3; bottom: 8px; left: 8px; -} -.zoom-controller-box { - position: absolute; - left: 76px; - z-index: 3; - bottom: 8px; + &.is-disabled { + display: none; + } } .page-controller-box { @@ -43,33 +40,9 @@ z-index: 3; bottom: 8px; right: 8px; -} -.page-controller-mid-box { - display: flex; - align-items: center; - justify-content: center; - background-color: white; - height: 32px; - padding-left: 4px; - padding-right: 4px; - border-radius: 4px; - user-select: none; - font-size: 12px; - box-shadow: 0 4px 12px 0 rgba(0, 0, 0, 0.08); -} - -.page-preview-cell { - width: 24px; - height: 24px; - display: flex; - justify-content: center; - align-items: center; - cursor: pointer; - background-color: white; - border-radius: 2px; - &:hover { - background: rgba(33, 35, 36, 0.1); + &.is-disabled { + display: none; } } diff --git a/web/flat-web/src/components/Whiteboard.tsx b/web/flat-web/src/components/Whiteboard.tsx index e84a03dfb1c..de53777f72c 100644 --- a/web/flat-web/src/components/Whiteboard.tsx +++ b/web/flat-web/src/components/Whiteboard.tsx @@ -1,16 +1,15 @@ -import PageController from "@netless/page-controller"; -import PreviewController from "@netless/preview-controller"; +import "@netless/window-manager/dist/style.css"; +import "./Whiteboard.less"; + import RedoUndo from "@netless/redo-undo"; import ToolBox from "@netless/tool-box"; -import ZoomController from "@netless/zoom-controller"; +import { WindowManager } from "@netless/window-manager"; import classNames from "classnames"; import { observer } from "mobx-react-lite"; import React, { useCallback } from "react"; -import { RoomPhase } from "white-web-sdk"; -import pagesSVG from "../assets/image/pages.svg"; import { WhiteboardStore } from "../stores/WhiteboardStore"; import { isSupportedImageType, onDropImage } from "../utils/dnd/image"; -import "./Whiteboard.less"; +import { ScenesController } from "../../../../packages/flat-components/src"; export interface WhiteboardProps { whiteboardStore: WhiteboardStore; @@ -20,14 +19,22 @@ export const Whiteboard = observer(function Whiteboard({ whiteb const { room } = whiteboardStore; const bindWhiteboard = useCallback( - (ref: HTMLDivElement) => { - if (room) { - room.bindHtmlElement(ref); - if (room.phase === RoomPhase.Connected) { - room.scalePptToFit(); - } + async (ref: HTMLDivElement | null) => { + if (ref && room) { + await WindowManager.mount({ + room, + container: ref, + collectorStyles: { + position: "absolute", + right: "10px", + bottom: "60px", + }, + }); + whiteboardStore.onMainViewModeChange(); + whiteboardStore.onWindowManagerBoxStateChange(); } }, + // eslint-disable-next-line react-hooks/exhaustive-deps [room], ); @@ -66,37 +73,31 @@ export const Whiteboard = observer(function Whiteboard({ whiteb onDragOver={onDragOver} onDrop={onDrop} > -
- -
-
+
-
-
- -
- {"pages"} -
-
+
+
- - {/* */}
diff --git a/web/flat-web/src/pages/CloudStoragePage/CloudStoragePanel.tsx b/web/flat-web/src/pages/CloudStoragePage/CloudStoragePanel.tsx index 4e745c75a0a..6409c8a1f30 100644 --- a/web/flat-web/src/pages/CloudStoragePage/CloudStoragePanel.tsx +++ b/web/flat-web/src/pages/CloudStoragePage/CloudStoragePanel.tsx @@ -9,7 +9,7 @@ import { CloudStorageStore, CloudStorageFile } from "./store"; import { queryConvertingTaskStatus } from "../../apiMiddleware/courseware-converting"; import { convertFinish } from "../../apiMiddleware/flatServer/storage"; import { useIsomorphicLayoutEffect } from "react-use"; -import { RoomPhase, SceneDefinition } from "white-web-sdk"; +import { SceneDefinition } from "white-web-sdk"; import { CloudStorageContainer } from "flat-components"; import { useTranslation } from "react-i18next"; import { RequestErrorCode } from "../../constants/ErrorCode"; @@ -55,12 +55,9 @@ export const CloudStoragePanel = observer(function Cloud await insertImage(file); break; } - case ".mp3": { - insertAudio(file); - break; - } + case ".mp3": case ".mp4": { - insertVideo(file); + insertMediaFile(file); break; } case ".doc": @@ -84,6 +81,8 @@ export const CloudStoragePanel = observer(function Cloud } async function insertImage(file: CloudStorageFile): Promise { + await whiteboard?.switchMainViewToWriter(); + const room = whiteboard?.room; if (!room) { return; @@ -124,34 +123,8 @@ export const CloudStoragePanel = observer(function Cloud room.completeImageUpload(uuid, file.fileURL); } - function insertAudio(file: CloudStorageFile): void { - const room = whiteboard?.room; - if (!room) { - return; - } - - room.insertPlugin("video.js", { - originX: -240, - originY: -43, - width: 480, - height: 86, - attributes: { src: file.fileURL }, - }); - } - - function insertVideo(file: CloudStorageFile): void { - const room = whiteboard?.room; - if (!room) { - return; - } - - room.insertPlugin("video.js", { - originX: -240, - originY: -135, - width: 480, - height: 270, - attributes: { src: file.fileURL }, - }); + function insertMediaFile(file: CloudStorageFile): void { + whiteboard?.openMediaFileInWindowManager(file.fileURL, file.fileName); } async function insertDocs(file: CloudStorageFile, ext: string): Promise { @@ -200,19 +173,17 @@ export const CloudStoragePanel = observer(function Cloud f => ({ name: v4uuid(), ppt: { + src: f.conversionFileUrl, width: f.width, height: f.height, - src: f.conversionFileUrl, previewURL: f.preview, }, }), ); + const uuid = v4uuid(); - room.putScenes(`/${taskUUID}/${uuid}`, scenes); - room.setScenePath(`/${taskUUID}/${uuid}/${scenes[0].name}`); - if (room.phase === RoomPhase.Connected) { - room.scalePptToFit(); - } + const scenesPath = `/${taskUUID}/${uuid}`; + whiteboard?.openDocsFileInWindowManager(scenesPath, file.fileName, scenes); } else { void message.error(t("unable-to-insert-courseware")); } diff --git a/web/flat-web/src/stores/WhiteboardStore.ts b/web/flat-web/src/stores/WhiteboardStore.ts index 37774f8a50f..d81bca83af0 100644 --- a/web/flat-web/src/stores/WhiteboardStore.ts +++ b/web/flat-web/src/stores/WhiteboardStore.ts @@ -8,7 +8,9 @@ import { Room, RoomPhase, RoomState, + SceneDefinition, ViewMode, + ViewVisionMode, WhiteWebSdk, } from "white-web-sdk"; import { @@ -22,20 +24,27 @@ import { globalStore } from "./GlobalStore"; import { isMobile, isWindows } from "react-device-detect"; import { debounce } from "lodash-es"; import { coursewarePreloader } from "../utils/CoursewarePreloader"; +import { WindowManager, BuiltinApps } from "@netless/window-manager"; export class WhiteboardStore { public room: Room | null = null; public phase: RoomPhase = RoomPhase.Connecting; public viewMode: ViewMode | null = null; + public windowManager: WindowManager | null = null; public isWritable: boolean; public isShowPreviewPanel = false; public isFileOpen = false; public isKicked = false; + public isFocusWindow = false; + public isWindowMaximization = false; + public currentSceneIndex = 0; + public scenesCount = 0; /** is room Creator */ public readonly isCreator: boolean; + public readonly isSpeaker?: boolean; - public constructor(config: { isCreator: boolean }) { + public constructor(config: { isCreator: boolean; isSpeaker?: boolean }) { this.isCreator = config.isCreator; this.isWritable = config.isCreator; @@ -71,6 +80,26 @@ export class WhiteboardStore { } }; + public updateWindowManager = (windowManager: WindowManager): void => { + this.windowManager = windowManager; + }; + + public updateCurrentSceneIndex = (currentSceneIndex: number): void => { + this.currentSceneIndex = currentSceneIndex; + }; + + public updateScenesCount = (scenesCount: number): void => { + this.scenesCount = scenesCount; + }; + + public updateWindowMaximization = (isMaximization: boolean): void => { + this.isWindowMaximization = isMaximization; + }; + + public updateFocusWindow = (isFocus: boolean): void => { + this.isFocusWindow = isFocus; + }; + public setFileOpen = (open: boolean): void => { this.isFileOpen = open; }; @@ -87,6 +116,97 @@ export class WhiteboardStore { this.isShowPreviewPanel = show; }; + public setWindowReadonlyState = (isReadonly: boolean): void => { + if (this.windowManager) { + this.windowManager.setReadonly(isReadonly); + } + }; + + public switchMainViewToWriter = async (): Promise => { + if (this.windowManager && this.isFocusWindow) { + await this.windowManager.switchMainViewToWriter(); + } + }; + + public addMainViewScene = (): void => { + if (this.room && this.windowManager) { + const currentScene = this.currentSceneIndex + 1; + const scenePath = this.room.state.sceneState.scenePath; + const pathName = this.scenesPathName(scenePath); + + this.room.putScenes(pathName, [{}], currentScene); + this.windowManager.setMainViewSceneIndex(this.currentSceneIndex + 1); + } + }; + + public preMainViewScene = (): void => { + if (this.windowManager && this.currentSceneIndex > 0) { + this.windowManager.setMainViewSceneIndex(this.currentSceneIndex - 1); + } + }; + + public nextMainViewScene = (): void => { + if (this.windowManager && this.currentSceneIndex < this.scenesCount - 1) { + this.windowManager.setMainViewSceneIndex(this.currentSceneIndex + 1); + } + }; + + public openDocsFileInWindowManager = async ( + scenePath: string, + title: string, + scenes: SceneDefinition[], + ): Promise => { + try { + await this.windowManager?.addApp({ + kind: BuiltinApps.DocsViewer, + options: { + scenePath, + title, + scenes: scenes, + }, + }); + } catch (err) { + console.log(err); + } + }; + + public openMediaFileInWindowManager = async ( + resourceSrc: string, + title: string, + ): Promise => { + try { + await this.windowManager?.addApp({ + kind: BuiltinApps.MediaPlayer, + options: { + title, + }, + attributes: { + src: resourceSrc, + }, + }); + } catch (err) { + console.log(err); + } + }; + + public onMainViewModeChange = (): void => { + this.windowManager?.emitter.on("mainViewModeChange", mode => { + const isWindow = mode !== ViewVisionMode.Writable; + this.updateFocusWindow(isWindow); + if (!isWindow && this.room) { + this.updateCurrentSceneIndex(this.room.state.sceneState.index); + this.updateScenesCount(this.room.state.sceneState.scenes.length); + } + }); + }; + + public onWindowManagerBoxStateChange = (): void => { + this.windowManager?.emitter.on("boxStateChange", mode => { + const isMaximization = mode === "maximized"; + this.updateWindowMaximization(isMaximization); + }); + }; + public async joinWhiteboardRoom(): Promise { if (!globalStore.userUUID) { throw new Error("Missing userUUID"); @@ -148,6 +268,8 @@ export class WhiteboardStore { changeToArrow: "a", changeToHand: "h", }, + useMultiViews: true, + invisiblePlugins: [WindowManager], }, { onPhaseChanged: phase => { @@ -166,6 +288,14 @@ export class WhiteboardStore { console.log(err); } } + + if ( + this.room && + this.windowManager?.mainView.mode === ViewVisionMode.Writable + ) { + this.updateCurrentSceneIndex(this.room.state.sceneState.index); + this.updateScenesCount(this.room.state.sceneState.scenes.length); + } }, onDisconnectWithError: error => { console.error(error); @@ -213,18 +343,29 @@ export class WhiteboardStore { this.updateRoom(room); + this.updateCurrentSceneIndex(room.state.sceneState.index); + + this.updateScenesCount(room.state.sceneState.scenes.length); + + if (this.room) { + const windowManager = this.room.getInvisiblePlugin(WindowManager.kind) as WindowManager; + this.updateWindowManager(windowManager); + } + if (NODE_ENV === "development") { (window as any).room = room; + (window as any).manager = this.windowManager; } } public destroy(): void { - if (this.room) { - this.preloadPPTResource.cancel(); - this.room.callbacks.off(); - } + this.preloadPPTResource.cancel(); + this.windowManager?.destroy(); + this.room?.callbacks.off(); + if (NODE_ENV === "development") { (window as any).room = null; + (window as any).manager = null; } console.log(`Whiteboard unloaded: ${globalStore.whiteboardRoomUUID}`); } @@ -232,4 +373,14 @@ export class WhiteboardStore { private preloadPPTResource = debounce(async (pptSrc: string): Promise => { await coursewarePreloader.preload(pptSrc); }, 2000); + + // TODO: The method is ambiguous + private scenesPathName = (scenePath: string): string => { + const cells = scenePath.split("/"); + const popCell = cells.pop(); + if (popCell === "") { + cells.pop(); + } + return cells.join("/"); + }; } diff --git a/yarn.lock b/yarn.lock index 7d818b7553c..126b5e3c14b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1857,6 +1857,19 @@ call-me-maybe "^1.0.1" glob-to-regexp "^0.3.0" +"@netless/app-docs-viewer@^0.1.15": + version "0.1.15" + resolved "https://registry.npmjs.org/@netless/app-docs-viewer/-/app-docs-viewer-0.1.15.tgz#8b857c2d2e07889a621b87fde339e8bb3526465e" + integrity sha512-GZuevbDpU4sIyhN8SNrXW247dJmp5OsI18tiHFEU12fXDixwamKqCA3TNiuWD6+C8GmEcs/NvGeAI/yDui9WrA== + dependencies: + debounce-fn "^5.0.0" + vanilla-lazyload "^17.4.0" + +"@netless/app-media-player@0.1.0-beta.4": + version "0.1.0-beta.4" + resolved "https://registry.npmjs.org/@netless/app-media-player/-/app-media-player-0.1.0-beta.4.tgz#2283b8a1e0a104bd8d36a5dbe9798309041e262c" + integrity sha512-mwBrhITav9moFRS9lGmsWnLN1jBJhTjEfnQAVyLCjQvrzGGvZl+bakTSLhaazWvmdbo/V9YKoP0JlbytwAMHlg== + "@netless/canvas-polyfill@^0.0.4": version "0.0.4" resolved "https://registry.yarnpkg.com/@netless/canvas-polyfill/-/canvas-polyfill-0.0.4.tgz#b5f28eefeb9c1e8ff8253fa1b044ccb1dc1b7c9c" @@ -1888,18 +1901,6 @@ dependencies: query-string "^6.13.1" -"@netless/menu-box@^0.0.6": - version "0.0.6" - resolved "https://registry.yarnpkg.com/@netless/menu-box/-/menu-box-0.0.6.tgz#2460ff7ddef6c07066ba1036ff15bfc647bbee28" - integrity sha512-ShiDPCFa4yk6JaP45DCiKr2Iyg7cmwP7fvO7/TkxEiaNWJJpNdPsFwlqzaE64p0INT5Jw0hGy0osNpYIhIfvhQ== - dependencies: - react-burger-menu "^2.7.1" - -"@netless/page-controller@^0.0.4": - version "0.0.4" - resolved "https://registry.yarnpkg.com/@netless/page-controller/-/page-controller-0.0.4.tgz#6f21140f35a279fc37db69f66332d187d180e5ae" - integrity sha512-eDGwbBSpIZB6efrQlTz+sO4oei6Zroiz7IslAxQVFBzmgUnLrbcYyjJm+oz4pP8u+PfyWEKdc6gJzh3kND1iIw== - "@netless/player-controller@^0.0.9": version "0.0.9" resolved "https://registry.yarnpkg.com/@netless/player-controller/-/player-controller-0.0.9.tgz#2c2bad03d1d51c623a09cfa3e36a022809242fbb" @@ -1908,18 +1909,19 @@ "@ant-design/icons" "^4.5.0" "@netless/combine-player" "^1.1.3" -"@netless/preview-controller@^0.0.9": - version "0.0.9" - resolved "https://registry.yarnpkg.com/@netless/preview-controller/-/preview-controller-0.0.9.tgz#9b58c5eb360f76adcec7bfa86370488a1eae0531" - integrity sha512-F50uo/GF3dO9tSm3Lt2jlUNau59sie3uSigQ6g6XJpw74TfPBxn4I7ZVQk84Y576nuahGGdWrBaH0jcrFDN/BQ== - dependencies: - "@netless/menu-box" "^0.0.6" - "@netless/redo-undo@^0.0.5": version "0.0.5" resolved "https://registry.yarnpkg.com/@netless/redo-undo/-/redo-undo-0.0.5.tgz#c5b00f5940ef33a0d6a810cd0935f4d9c172ea52" integrity sha512-P8ceK3hSY2eMfFIjBeSpRsqXpjjTea9bBWyRF8t8q0kLR4ICld2VMFMRbytqZ8sjCFy9CgbicuBOdMj7juABIQ== +"@netless/telebox-insider@^0.1.14": + version "0.1.14" + resolved "https://registry.npmjs.org/@netless/telebox-insider/-/telebox-insider-0.1.14.tgz#7a1bd3979d0d24341db1163e8dd5735615a6a340" + integrity sha512-B0AwEPsRVTyg2MzdSbG9tfw7BYi1/wPEpeO2QAM9MZIN53fSO9BOA7X42hMafsEpXZ9p8PDJ29AbuGullEEV0Q== + dependencies: + eventemitter3 "^4.0.7" + stylefire "^7.0.3" + "@netless/tool-box@^0.1.4", "@netless/tool-box@^0.1.5": version "0.1.5" resolved "https://registry.yarnpkg.com/@netless/tool-box/-/tool-box-0.1.5.tgz#39977a0075c069aab90895bcee6268a8e6bf8afd" @@ -1930,16 +1932,24 @@ resolved "https://registry.yarnpkg.com/@netless/video-js-plugin/-/video-js-plugin-0.3.7.tgz#6c1f174f20e8a93634e1770e7e535c1302bdf22b" integrity sha512-UG1t9464w1bZT9kzdhxj/K7R6jqI9sqYfqfUQJ2w9JRWsNibL6O16OC81iwBJT6nkGXEVN7z2pqHvNg1OhKppw== +"@netless/window-manager@^0.1.41": + version "0.1.41" + resolved "https://registry.npmjs.org/@netless/window-manager/-/window-manager-0.1.41.tgz#7be690f01cae68b749897306b9341eb8a81772f4" + integrity sha512-FIJEYIP3yzAqJwFnGCunD70+2iVs8RpVEhWV1uqS05XyH+IWpgBFplmZzB4vAcVOuOWn4mGoGClcMfuUFUL/Nw== + dependencies: + "@netless/app-docs-viewer" "^0.1.15" + "@netless/app-media-player" "0.1.0-beta.4" + "@netless/telebox-insider" "^0.1.14" + emittery "^0.9.2" + lodash-es "^4.17.21" + nanoid "^3.1.25" + video.js ">=7" + "@netless/xml-js@1.6.15": version "1.6.15" resolved "https://registry.npmjs.org/@netless/xml-js/-/xml-js-1.6.15.tgz#46516d547b21149bcca732bb199d664791b3240a" integrity sha512-e0emMs7YtDB/ATUns1SJ61R9n9nfVvwwFodoc539Qt0ScksaCLCaFWgpEbLloj9sr60ry6Xd8QFHKULFIZB6zA== -"@netless/zoom-controller@^0.1.1": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@netless/zoom-controller/-/zoom-controller-0.1.1.tgz#7386aa13b815e030cc69a29041a819a6ca4fc7aa" - integrity sha512-/ZOzy1AHs2Q6ZjFpazIche4i6904QM773EniWfYR0QnGfp7TwgCA8wNbfD1yMQIX49fOfWR3FQI0RlRN0hVn9w== - "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -1991,6 +2001,22 @@ resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.17.tgz#25fdbdfd282c2f86ddf3fcefbd98be99cd2627e2" integrity sha512-0p1rCgM3LLbAdwBnc7gqgnvjHg9KpbhcSphergHShlkWz8EdPawoMJ3/VbezI0mGC5eKCDzMaPgF9Yca6cKvrg== +"@popmotion/easing@^1.0.1": + version "1.0.2" + resolved "https://registry.npmjs.org/@popmotion/easing/-/easing-1.0.2.tgz#17d925c45b4bf44189e5a38038d149df42d8c0b4" + integrity sha512-IkdW0TNmRnWTeWI7aGQIVDbKXPWHVEYdGgd5ZR4SH/Ty/61p63jCjrPxX1XrR7IGkl08bjhJROStD7j+RKgoIw== + +"@popmotion/popcorn@^0.4.4": + version "0.4.4" + resolved "https://registry.npmjs.org/@popmotion/popcorn/-/popcorn-0.4.4.tgz#a5f906fccdff84526e3fcb892712d7d8a98d6adc" + integrity sha512-jYO/8319fKoNLMlY4ZJPiPu8Ea8occYwRZhxpaNn/kZsK4QG2E7XFlXZMJBsTWDw7I1i0uaqyC4zn1nwEezLzg== + dependencies: + "@popmotion/easing" "^1.0.1" + framesync "^4.0.1" + hey-listen "^1.0.8" + style-value-types "^3.1.7" + tslib "^1.10.0" + "@popperjs/core@^2.5.4", "@popperjs/core@^2.6.0": version "2.9.3" resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.9.3.tgz#8b68da1ebd7fc603999cf6ebee34a4899a14b88e" @@ -4132,11 +4158,6 @@ ali-oss@^6.15.2: utility "^1.8.0" xml2js "^0.4.16" -amdefine@>=0.0.4: - version "1.0.1" - resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" - integrity sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU= - ansi-align@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.0.tgz#b536b371cf687caaef236c18d3e21fe3797467cb" @@ -4558,15 +4579,6 @@ assign-symbols@^1.0.0: resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= -ast-transform@0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/ast-transform/-/ast-transform-0.0.0.tgz#74944058887d8283e189d954600947bc98fe0062" - integrity sha1-dJRAWIh9goPhidlUYAlHvJj+AGI= - dependencies: - escodegen "~1.2.0" - esprima "~1.0.4" - through "~2.3.4" - ast-types-flow@^0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad" @@ -4586,11 +4598,6 @@ ast-types@^0.14.2: dependencies: tslib "^2.0.1" -ast-types@^0.7.0: - version "0.7.8" - resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.7.8.tgz#902d2e0d60d071bdcd46dc115e1809ed11c138a9" - integrity sha1-kC0uDWDQcb3NRtwRXhgJ7RHBOKk= - astral-regex@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" @@ -5076,13 +5083,6 @@ brorand@^1.0.1, brorand@^1.1.0: resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= -browser-resolve@^1.8.1: - version "1.11.3" - resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.3.tgz#9b7cbb3d0f510e4cb86bdbd796124d28b5890af6" - integrity sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ== - dependencies: - resolve "1.1.7" - browserify-aes@^1.0.0, browserify-aes@^1.0.4: version "1.2.0" resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" @@ -5114,15 +5114,6 @@ browserify-des@^1.0.0: inherits "^2.0.1" safe-buffer "^5.1.2" -browserify-optional@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/browserify-optional/-/browserify-optional-1.0.1.tgz#1e13722cfde0d85f121676c2a72ced533a018869" - integrity sha1-HhNyLP3g2F8SFnbCpyztUzoBiGk= - dependencies: - ast-transform "0.0.0" - ast-types "^0.7.0" - browser-resolve "^1.8.1" - browserify-rsa@^4.0.0, browserify-rsa@^4.0.1: version "4.1.0" resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.1.0.tgz#b2fd06b5b75ae297f7ce2dc651f918f5be158c8d" @@ -6476,6 +6467,13 @@ dayjs@1.x: resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.10.6.tgz#288b2aa82f2d8418a6c9d4df5898c0737ad02a63" integrity sha512-AztC/IOW4L1Q41A86phW5Thhcrco3xuAA+YX/BLpLWWjRcTj5TOt/QImBLmCKlrF7u7k47arTnOyL6GnbG8Hvw== +debounce-fn@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/debounce-fn/-/debounce-fn-5.0.0.tgz#1375e6b64a871e6fb6967c6ee05efbac08b65d9e" + integrity sha512-y0u25m4GMdDJ1oHX4ziszas15E4ryNoeFkQuZM/Z6yTy8jB8ity/jqSNWnQUi/csBBaQIad6Zd8eI1xKwtbFzw== + dependencies: + mimic-fn "^3.0.0" + debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -7190,6 +7188,11 @@ elliptic@^6.5.3: minimalistic-assert "^1.0.1" minimalistic-crypto-utils "^1.0.1" +emittery@^0.9.2: + version "0.9.2" + resolved "https://registry.npmjs.org/emittery/-/emittery-0.9.2.tgz#0a57c40773c6da380115c85bd67d381dd9e22f6f" + integrity sha512-sweWHu3j4dQm+NjLPu17pv+m5lCeK7g4Ov0NgfbRUEyzLc59DYDeRYXqlxEvuolaToI0VR3ThjFAghzl7Acjfw== + "emoji-regex@>=6.0.0 <=6.1.1": version "6.1.1" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-6.1.1.tgz#c6cd0ec1b0642e2a3c67a1137efc5e796da4f88e" @@ -7481,17 +7484,6 @@ escodegen@^2.0.0: optionalDependencies: source-map "~0.6.1" -escodegen@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.2.0.tgz#09de7967791cc958b7f89a2ddb6d23451af327e1" - integrity sha1-Cd55Z3kcyVi3+Jot220jRRrzJ+E= - dependencies: - esprima "~1.0.4" - estraverse "~1.5.0" - esutils "~1.0.0" - optionalDependencies: - source-map "~0.1.30" - eslint-config-prettier@^8.3.0: version "8.3.0" resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz#f7471b20b6fe8a9a9254cc684454202886a2dd7a" @@ -7739,11 +7731,6 @@ esprima@^4.0.0, esprima@^4.0.1: resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esprima@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-1.0.4.tgz#9f557e08fc3b4d26ece9dd34f8fbf476b62585ad" - integrity sha1-n1V+CPw7TSbs6d00+Pv0drYlha0= - esquery@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" @@ -7768,11 +7755,6 @@ estraverse@^5.1.0, estraverse@^5.2.0: resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== -estraverse@~1.5.0: - version "1.5.1" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.5.1.tgz#867a3e8e58a9f84618afb6c2ddbcd916b7cbaf71" - integrity sha1-hno+jlip+EYYr7bC3bzZFrfLr3E= - estree-to-babel@^3.1.0: version "3.2.1" resolved "https://registry.yarnpkg.com/estree-to-babel/-/estree-to-babel-3.2.1.tgz#82e78315275c3ca74475fdc8ac1a5103c8a75bf5" @@ -7792,21 +7774,11 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== -esutils@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-1.0.0.tgz#8151d358e20c8acc7fb745e7472c0025fe496570" - integrity sha1-gVHTWOIMisx/t0XnRywAJf5JZXA= - etag@~1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= -eve@~0.5.1: - version "0.5.4" - resolved "https://registry.yarnpkg.com/eve/-/eve-0.5.4.tgz#67d080b9725291d7e389e34c26860dd97f1debaa" - integrity sha1-Z9CAuXJSkdfjieNMJoYN2X8d66o= - eventemitter3@^4.0.0, eventemitter3@^4.0.7: version "4.0.7" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" @@ -8419,6 +8391,13 @@ fragment-cache@^0.2.1: dependencies: map-cache "^0.2.2" +framesync@^4.0.0, framesync@^4.0.1: + version "4.1.0" + resolved "https://registry.npmjs.org/framesync/-/framesync-4.1.0.tgz#69a8db3ca432dc70d6a76ba882684a1497ef068a" + integrity sha512-MmgZ4wCoeVxNbx2xp5hN/zPDCbLSKiDt4BbbslK7j/pM2lg5S0vhTNv1v8BCVb99JPIo6hXBFdwzU7Q4qcAaoQ== + dependencies: + hey-listen "^1.0.5" + fresh@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" @@ -9203,6 +9182,11 @@ he@^1.2.0: resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== +hey-listen@^1.0.5, hey-listen@^1.0.8: + version "1.0.8" + resolved "https://registry.npmjs.org/hey-listen/-/hey-listen-1.0.8.tgz#8e59561ff724908de1aa924ed6ecc84a56a9aa68" + integrity sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q== + highlight.js@^10.1.1, highlight.js@~10.7.0: version "10.7.3" resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531" @@ -9229,7 +9213,7 @@ hmac-drbg@^1.0.1: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" -hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1: +hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1: version "3.3.2" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== @@ -11387,7 +11371,7 @@ mimic-fn@^2.0.0, mimic-fn@^2.1.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== -mimic-fn@^3.1.0: +mimic-fn@^3.0.0, mimic-fn@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-3.1.0.tgz#65755145bbf3e36954b949c16450427451d5ca74" integrity sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ== @@ -11533,27 +11517,14 @@ mobx-react-lite@^3.2.0: resolved "https://registry.yarnpkg.com/mobx-react-lite/-/mobx-react-lite-3.2.0.tgz#331d7365a6b053378dfe9c087315b4e41c5df69f" integrity sha512-q5+UHIqYCOpBoFm/PElDuOhbcatvTllgRp3M1s+Hp5j0Z6XNgDbgqxawJ0ZAUEyKM8X1zs70PCuhAIzX1f4Q/g== -mobx-react@^5.4.4: - version "5.4.4" - resolved "https://registry.yarnpkg.com/mobx-react/-/mobx-react-5.4.4.tgz#b3de9c6eabcd0ed8a40036888cb0221ab9568b80" - integrity sha512-2mTzpyEjVB/RGk2i6KbcmP4HWcAUFox5ZRCrGvSyz49w20I4C4qql63grPpYrS9E9GKwgydBHQlA4y665LuRCQ== - dependencies: - hoist-non-react-statics "^3.0.0" - react-lifecycles-compat "^3.0.2" - -mobx-react@^7.1.0: +mobx-react@^7.1.0, mobx-react@^7.2.0: version "7.2.0" resolved "https://registry.yarnpkg.com/mobx-react/-/mobx-react-7.2.0.tgz#241e925e963bb83a31d269f65f9f379e37ecbaeb" integrity sha512-KHUjZ3HBmZlNnPd1M82jcdVsQRDlfym38zJhZEs33VxyVQTvL77hODCArq6+C1P1k/6erEeo2R7rpE7ZeOL7dg== dependencies: mobx-react-lite "^3.2.0" -mobx@^4.15.7: - version "4.15.7" - resolved "https://registry.yarnpkg.com/mobx/-/mobx-4.15.7.tgz#933281268c3b4658b6cf2526e872cf78ea48ab95" - integrity sha512-X4uQvuf2zYKHVO5kRT5Utmr+J9fDnRgxWWnSqJ4oiccPTQU38YG+/O3nPmOhUy4jeHexl7XJJpWDBgEnEfp+8w== - -mobx@^6.1.0: +mobx@^6.1.0, mobx@^6.3.2: version "6.3.2" resolved "https://registry.yarnpkg.com/mobx/-/mobx-6.3.2.tgz#125590961f702a572c139ab69392bea416d2e51b" integrity sha512-xGPM9dIE1qkK9Nrhevp0gzpsmELKU4MFUJRORW/jqxVFIHHWIoQrjDjL8vkwoJYY3C2CeVJqgvl38hgKTalTWg== @@ -11696,7 +11667,7 @@ nano-css@^5.3.1: stacktrace-js "^2.0.2" stylis "^4.0.6" -nanoid@^3.1.23: +nanoid@^3.1.23, nanoid@^3.1.25: version "3.1.25" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.25.tgz#09ca32747c0e543f0e1814b7d3793477f9c8e152" integrity sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q== @@ -12006,11 +11977,6 @@ number-is-nan@^1.0.0: resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= -numeric@^1.2.6: - version "1.2.6" - resolved "https://registry.yarnpkg.com/numeric/-/numeric-1.2.6.tgz#765b02bef97988fcf880d4eb3f36b80fa31335aa" - integrity sha1-dlsCvvl5iPz4gNTrPza4D6MTNao= - oauth-sign@~0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" @@ -13654,17 +13620,6 @@ rc@^1.2.8: minimist "^1.2.0" strip-json-comments "~2.0.1" -react-burger-menu@^2.7.1: - version "2.9.2" - resolved "https://registry.yarnpkg.com/react-burger-menu/-/react-burger-menu-2.9.2.tgz#7eaa1c040b9543f1de6dd5f8fd237fbff0655f13" - integrity sha512-NOVV0Svjydlo8b/Twd/BQZ7WYr6T5rdVtxTsS7iESFCdQekaK8DIZt78D+qFS4eUjy8q/VQ2H3SLy/xir/NN8Q== - dependencies: - browserify-optional "^1.0.0" - classnames "^2.2.6" - eve "~0.5.1" - prop-types "^15.7.2" - snapsvg-cjs "0.0.6" - react-colorful@^5.1.2: version "5.3.0" resolved "https://registry.yarnpkg.com/react-colorful/-/react-colorful-5.3.0.tgz#bcbae49c1affa9ab9a3c8063398c5948419296bd" @@ -13830,7 +13785,7 @@ react-is@^17.0.2: resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== -react-lifecycles-compat@^3.0.2, react-lifecycles-compat@^3.0.4: +react-lifecycles-compat@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== @@ -14425,11 +14380,6 @@ resolve-url@^0.2.1: resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= -resolve@1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" - integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= - resolve@^1.1.6, resolve@^1.10.0, resolve@^1.12.0, resolve@^1.14.2, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.3.2, resolve@^1.8.1, resolve@^1.9.0: version "1.20.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" @@ -15066,20 +15016,6 @@ snapdragon@^0.8.1: source-map-resolve "^0.5.0" use "^3.1.0" -snapsvg-cjs@0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/snapsvg-cjs/-/snapsvg-cjs-0.0.6.tgz#3b2f56af2573d3d364c3ed5bf8885745f4d2dde1" - integrity sha1-Oy9WryVz09Nkw+1b+IhXRfTS3eE= - dependencies: - snapsvg "0.5.1" - -snapsvg@0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/snapsvg/-/snapsvg-0.5.1.tgz#0caf52c79189a290746fc446cc5e863f6bdddfe3" - integrity sha1-DK9Sx5GJopB0b8RGzF6GP2vd3+M= - dependencies: - eve "~0.5.1" - sockjs-client@^1.5.0: version "1.5.1" resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.5.1.tgz#256908f6d5adfb94dabbdbd02c66362cca0f9ea6" @@ -15193,13 +15129,6 @@ source-map@^0.7.3, source-map@~0.7.2: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== -source-map@~0.1.30: - version "0.1.43" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.43.tgz#c24bc146ca517c1471f5dacbe2571b2b7f9e3346" - integrity sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y= - dependencies: - amdefine ">=0.0.4" - sourcemap-codec@^1.4.4, sourcemap-codec@^1.4.8: version "1.4.8" resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" @@ -15693,6 +15622,25 @@ style-to-object@0.3.0, style-to-object@^0.3.0: dependencies: inline-style-parser "0.1.1" +style-value-types@^3.1.7: + version "3.2.0" + resolved "https://registry.npmjs.org/style-value-types/-/style-value-types-3.2.0.tgz#eb89cab1340823fa7876f3e289d29d99c92111bb" + integrity sha512-ih0mGsrYYmVvdDi++/66O6BaQPRPRMQHoZevNNdMMcPlP/cH28Rnfsqf1UEba/Bwfuw9T8BmIMwbGdzsPwQKrQ== + dependencies: + hey-listen "^1.0.8" + tslib "^1.10.0" + +stylefire@^7.0.3: + version "7.0.3" + resolved "https://registry.npmjs.org/stylefire/-/stylefire-7.0.3.tgz#9120ecbb084111788e0ddaa04074799750f20d1d" + integrity sha512-Q0l7NSeFz/OkX+o6/7Zg3VZxSAZeQzQpYomWmIpOehFM/rJNMSLVX5fgg6Q48ut2ETNKwdhm97mPNU643EBCoQ== + dependencies: + "@popmotion/popcorn" "^0.4.4" + framesync "^4.0.0" + hey-listen "^1.0.8" + style-value-types "^3.1.7" + tslib "^1.10.0" + stylis@^4.0.6: version "4.0.10" resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.0.10.tgz#446512d1097197ab3f02fb3c258358c3f7a14240" @@ -15956,7 +15904,7 @@ through2@^4.0.0: dependencies: readable-stream "3" -"through@>=2.2.7 <3", through@^2.3.8, through@~2.3, through@~2.3.4: +"through@>=2.2.7 <3", through@^2.3.8, through@~2.3: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= @@ -16797,6 +16745,11 @@ value-equal@^1.0.1: resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-1.0.1.tgz#1e0b794c734c5c0cade179c437d356d931a34d6c" integrity sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw== +vanilla-lazyload@^17.4.0: + version "17.4.0" + resolved "https://registry.npmjs.org/vanilla-lazyload/-/vanilla-lazyload-17.4.0.tgz#09d65a5be46242b82b557b9ccd886613de76f4c2" + integrity sha512-4IVX93uLEgQGBdSCaSE1XJgeNNT1+sV8PKiImM21EkDGJBH3tTWL9wYrMA4xT5C2EIEfw8WkinUxUG+uMY2ZyA== + vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" @@ -16848,7 +16801,7 @@ video.js@7.10.2: videojs-font "3.2.0" videojs-vtt.js "^0.15.2" -"video.js@^6 || ^7", video.js@^7.8.4: +video.js@>=7, "video.js@^6 || ^7", video.js@^7.8.4: version "7.14.3" resolved "https://registry.yarnpkg.com/video.js/-/video.js-7.14.3.tgz#0b612c09a0a81ef9bce65c710e73291cb06dc32c" integrity sha512-6avCdSIfn5ss5NOgoQfY/xEfPNcz9DXSw+ZN80NwPguCdRd4VL4y40b/d7osYJwyCdF+YkvhqAW7dw4s0vBigg== @@ -17226,10 +17179,10 @@ which@^2.0.1, which@^2.0.2: dependencies: isexe "^2.0.0" -white-web-sdk@2.13.17: - version "2.13.17" - resolved "https://registry.npmjs.org/white-web-sdk/-/white-web-sdk-2.13.17.tgz#db120727a44668bc4657bf9f9f37f13751a5c289" - integrity sha512-maTRDflywNh8jcNcfk7yZndzuKQfSADHMEjcNZiNeiuYYPcXzRv3tAjXBZfR0jBoZ/Mdml5ZeGiGvifh6ZLobQ== +white-web-sdk@2.13.19: + version "2.13.19" + resolved "https://registry.npmjs.org/white-web-sdk/-/white-web-sdk-2.13.19.tgz#2d0a45518f5e54c9283ffe770570b02db8785965" + integrity sha512-hIV59tvIPUOeGVlqDIp7bb7HilPYJfvMH6Op3Od6yauOR3ss18E1ftaDN+qPn3Ys7A+FkvP1BwKNkYezHiQ5mw== dependencies: "@netless/canvas-polyfill" "^0.0.4" "@netless/xml-js" "1.6.15" @@ -17240,9 +17193,8 @@ white-web-sdk@2.13.17: detect-it "^3.0.5" eventemitter3 "^4.0.7" mathjs "6.6.5" - mobx "^4.15.7" - mobx-react "^5.4.4" - numeric "^1.2.6" + mobx "^6.3.2" + mobx-react "^7.2.0" protobufjs "^6.11.2" query-string "5" react "^16.8.0"