From 49c4ccbdcdcb645f06127e1dbee8700ead86ed83 Mon Sep 17 00:00:00 2001 From: hyrious Date: Fri, 24 Mar 2023 15:50:10 +0800 Subject: [PATCH] refactor(flat-components): show avatar windows that has left --- .../ClassroomPage/AvatarWindow/index.tsx | 3 - .../ClassroomPage/AvatarWindow/style.less | 4 - .../ClassroomPage/VideoAvatarAbsent/index.tsx | 90 +++++++++++++++++-- .../VideoAvatarAbsent/style.less | 33 ++++++- .../src/components/UsersPanel/index.tsx | 2 +- packages/flat-i18n/locales/en.json | 4 +- packages/flat-i18n/locales/zh-CN.json | 4 +- .../src/components/RTCAvatar/index.tsx | 6 ++ .../flat-pages/src/components/UserWindows.tsx | 5 +- 9 files changed, 125 insertions(+), 26 deletions(-) diff --git a/packages/flat-components/src/components/ClassroomPage/AvatarWindow/index.tsx b/packages/flat-components/src/components/ClassroomPage/AvatarWindow/index.tsx index 28c918893d2..5e942d811b8 100644 --- a/packages/flat-components/src/components/ClassroomPage/AvatarWindow/index.tsx +++ b/packages/flat-components/src/components/ClassroomPage/AvatarWindow/index.tsx @@ -15,7 +15,6 @@ export interface AvatarWindowProps { mode: "normal" | "maximized"; rect: Rectangle; zIndex?: number; - hidden?: boolean; readonly?: boolean; onClick?: () => void; onResize?: (newRectangle: Rectangle, handle?: ResizeHandle) => void; @@ -37,7 +36,6 @@ export const AvatarWindow: React.FC = ({ mode, rect, zIndex, - hidden, readonly, children, onClick, @@ -189,7 +187,6 @@ export const AvatarWindow: React.FC = ({ "window-maximized": mode === "maximized", })} draggable={!readonly && mode === "maximized"} - hidden={hidden} style={ mode === "normal" ? { diff --git a/packages/flat-components/src/components/ClassroomPage/AvatarWindow/style.less b/packages/flat-components/src/components/ClassroomPage/AvatarWindow/style.less index d9d28f189dd..2a678be59c9 100644 --- a/packages/flat-components/src/components/ClassroomPage/AvatarWindow/style.less +++ b/packages/flat-components/src/components/ClassroomPage/AvatarWindow/style.less @@ -10,10 +10,6 @@ cursor: grab; } -.window[hidden] { - display: none; -} - .window-grabbing, .window-restoring { transition: none; diff --git a/packages/flat-components/src/components/ClassroomPage/VideoAvatarAbsent/index.tsx b/packages/flat-components/src/components/ClassroomPage/VideoAvatarAbsent/index.tsx index 52e9cf304ee..07e8115bfce 100644 --- a/packages/flat-components/src/components/ClassroomPage/VideoAvatarAbsent/index.tsx +++ b/packages/flat-components/src/components/ClassroomPage/VideoAvatarAbsent/index.tsx @@ -2,41 +2,113 @@ import "./style.less"; import Placeholder from "./icons/Placeholder"; +import classnames from "classnames"; import React, { FC, useContext } from "react"; +import { createPortal } from "react-dom"; import { useTranslate } from "@netless/flat-i18n"; -import classnames from "classnames"; import { User } from "../../../types/user"; import { DarkModeContext } from "../../FlatThemeProvider"; export interface VideoAvatarAbsentProps { avatarUser?: User | null; small?: boolean; + /** Is current user room creator */ + isCreator: boolean; + /** Is `avatarUser` room creator */ isAvatarUserCreator: boolean; + + portal?: HTMLElement | null; + onDoubleClick?: () => void; + onDragStart?: () => void; + onDragEnd?: () => void; + isDropTarget?: boolean; } export const VideoAvatarAbsent: FC = ({ avatarUser, small, + isCreator, isAvatarUserCreator, + portal, + onDoubleClick, + onDragStart, + onDragEnd, + isDropTarget, }) => { const t = useTranslate(); const isDark = useContext(DarkModeContext); - return ( + const onDragStartImpl = (ev: React.DragEvent): void => { + if (!avatarUser) { + return; + } + const rect = ev.currentTarget.getBoundingClientRect(); + const x = (ev.clientX - rect.left) / rect.width; + const y = (ev.clientY - rect.top) / rect.height; + ev.dataTransfer.setData("video-avatar", JSON.stringify([avatarUser.userUUID, x, y])); + ev.dataTransfer.effectAllowed = "move"; + onDragStart && onDragStart(); + }; + + const absentView = avatarUser ? ( +
+
+ {avatarUser.name} +
+

+ {avatarUser.name} +

+
+
{t("has-left")}
+
+ ) : null; + + return portal ? (
- {isAvatarUserCreator - ? t("teacher-left-temporarily") - : avatarUser - ? t("user-left-temporarily", { name: avatarUser.name }) - : t("student-left-temporarily")} + {isAvatarUserCreator ? ( + t("teacher-left-temporarily") + ) : avatarUser ? ( + <> + {avatarUser.name} + + {t("user-left-temporarily")} + + + ) : ( + t("student-left-temporarily") + )}
+ {absentView && portal && createPortal(absentView, portal)}
+ ) : ( + absentView ); }; diff --git a/packages/flat-components/src/components/ClassroomPage/VideoAvatarAbsent/style.less b/packages/flat-components/src/components/ClassroomPage/VideoAvatarAbsent/style.less index 7a6eaa2d8cc..b80fea0dc65 100644 --- a/packages/flat-components/src/components/ClassroomPage/VideoAvatarAbsent/style.less +++ b/packages/flat-components/src/components/ClassroomPage/VideoAvatarAbsent/style.less @@ -12,6 +12,10 @@ font-size: 12px; border-radius: 6px; } + + &.is-drop-target { + box-shadow: inset 0 0 0 2px var(--primary); + } } .video-avatar-absent-block { @@ -43,11 +47,38 @@ position: absolute; left: 50%; bottom: 0; - width: max-content; + width: 120px; + display: inline-flex; + align-items: center; + justify-content: center; + gap: 4px; transform: translateX(-50%); } } +.video-avatar-absent-name { + flex-shrink: 1; + overflow: hidden; + text-overflow: ellipsis; +} + +.video-avatar-absent-desc { + white-space: nowrap; +} + +.video-avatar-is-left { + background-color: rgba(0, 0, 0, .5); + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + display: flex; + align-items: center; + justify-content: center; + color: #fff; +} + .flat-color-scheme-dark { .video-avatar-absent { background: var(--grey-7); diff --git a/packages/flat-components/src/components/UsersPanel/index.tsx b/packages/flat-components/src/components/UsersPanel/index.tsx index 683d7c5474d..6bec9b5a08f 100644 --- a/packages/flat-components/src/components/UsersPanel/index.tsx +++ b/packages/flat-components/src/components/UsersPanel/index.tsx @@ -166,7 +166,7 @@ const Row = /* @__PURE__ */ observer(function Row({ {user.name} {isSelf && {t("me")}} - {t("offline")} + {t("has-left")}
) : ( diff --git a/packages/flat-i18n/locales/en.json b/packages/flat-i18n/locales/en.json index 661bae7239b..e71395f405e 100644 --- a/packages/flat-i18n/locales/en.json +++ b/packages/flat-i18n/locales/en.json @@ -26,7 +26,7 @@ "raise-your-hand": "Raise hand", "raise-hand": "Raise hand", "raised-hand": "Hand raised", - "has-left": "(Has left)", + "has-left": "Has left", "offline": "offline", "no-students": "No students", "no-one-raising-hand": "No one is raising hand", @@ -64,7 +64,7 @@ "student-sure-to-exit-the-room": "Sure to exit the room", "teacher-left-temporarily": "Teacher has left", "student-left-temporarily": "Student has left", - "user-left-temporarily": "{{name}} has left", + "user-left-temporarily": "has left", "the-room-has-ended-and-is-about-to-exit": "The room has ended and is about to exit...", "you-have-entered-the-room-at-another-device": "You have entered the room at another device", "class-picker-text": { diff --git a/packages/flat-i18n/locales/zh-CN.json b/packages/flat-i18n/locales/zh-CN.json index 39aa3a38c11..59009b927d1 100644 --- a/packages/flat-i18n/locales/zh-CN.json +++ b/packages/flat-i18n/locales/zh-CN.json @@ -25,7 +25,7 @@ "during-the-presentation": "(发言中)", "end": "结束", "raised-hand": "举手", - "has-left": "(已离开)", + "has-left": "已离开", "offline": "已离线", "no-students": "暂无学生", "no-one-raising-hand": "暂无学生举手", @@ -51,7 +51,7 @@ "you-have-entered-the-room-at-another-device": "你已在另外一台设备进入房间", "teacher-left-temporarily": "老师暂时离开", "student-left-temporarily": "学生暂时离开", - "user-left-temporarily": "{{name}} 暂时离开", + "user-left-temporarily": "已离开", "signal-text": "上行:{{up}},下行:{{down}}", "client-to-edge-server-network-latency": "客户端到边缘服务器的网络延迟", "delay": "延迟:", diff --git a/packages/flat-pages/src/components/RTCAvatar/index.tsx b/packages/flat-pages/src/components/RTCAvatar/index.tsx index 7364260a130..704f956ea5b 100644 --- a/packages/flat-pages/src/components/RTCAvatar/index.tsx +++ b/packages/flat-pages/src/components/RTCAvatar/index.tsx @@ -50,7 +50,13 @@ export const RTCAvatar: FC = /* @__PURE__ */ observer ); }, diff --git a/packages/flat-pages/src/components/UserWindows.tsx b/packages/flat-pages/src/components/UserWindows.tsx index 08c8189f4d5..26007d70b04 100644 --- a/packages/flat-pages/src/components/UserWindows.tsx +++ b/packages/flat-pages/src/components/UserWindows.tsx @@ -52,9 +52,7 @@ export const UserWindows = observer(function UserWindows({ cla return { userUUID, window: classroom.userWindows.get(userUUID) }; }); - const userWindowsLength = classroom.userWindowsGrid - ? classroom.userWindowsGrid.filter(userUUID => !classroom.userHasLeft(userUUID)).length - : 0; + const userWindowsLength = classroom.userWindowsGrid ? classroom.userWindowsGrid.length : 0; const paddings = useMemo(() => { if (!boundingRect) { @@ -276,7 +274,6 @@ const UserAvatarWindow = observer(function UserAvatarWind return (