Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(flat-components): show avatar windows that has left #1879

Merged
merged 1 commit into from
Mar 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -37,7 +36,6 @@ export const AvatarWindow: React.FC<AvatarWindowProps> = ({
mode,
rect,
zIndex,
hidden,
readonly,
children,
onClick,
Expand Down Expand Up @@ -189,7 +187,6 @@ export const AvatarWindow: React.FC<AvatarWindowProps> = ({
"window-maximized": mode === "maximized",
})}
draggable={!readonly && mode === "maximized"}
hidden={hidden}
style={
mode === "normal"
? {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@
cursor: grab;
}

.window[hidden] {
display: none;
}

.window-grabbing,
.window-restoring {
transition: none;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<VideoAvatarAbsentProps> = ({
avatarUser,
small,
isCreator,
isAvatarUserCreator,
portal,
onDoubleClick,
onDragStart,
onDragEnd,
isDropTarget,
}) => {
const t = useTranslate();
const isDark = useContext(DarkModeContext);

return (
const onDragStartImpl = (ev: React.DragEvent<HTMLDivElement>): 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 ? (
<div
className={classnames("video-avatar", {
"is-small": small && !portal,
"is-drop-target": isDropTarget,
})}
data-user-uuid={avatarUser.userUUID}
draggable={isCreator && !portal}
onDoubleClick={portal ? undefined : onDoubleClick}
onDragEnd={onDragEnd}
onDragStart={onDragStartImpl}
>
<div
className="video-avatar-image-blur-bg"
style={{ backgroundImage: `url(${avatarUser.avatar})` }}
/>
<img
alt={avatarUser.name}
className="video-avatar-image"
draggable={false}
src={avatarUser.avatar}
/>
<div className="video-avatar-bottom">
<h1 className="video-avatar-user-name" title={avatarUser.name}>
{avatarUser.name}
</h1>
</div>
<div className="video-avatar-is-left">{t("has-left")}</div>
</div>
) : null;

return portal ? (
<div
className={classnames("video-avatar-absent", { "is-small": small })}
data-user-uuid="[object Object]"
className={classnames("video-avatar-absent", {
"is-small": small,
"is-drop-target": isDropTarget,
})}
data-user-uuid={avatarUser?.userUUID}
>
<div className="video-avatar-absent-block">
<Placeholder className="video-avatar-absent-img" isDark={isDark} />
<span className="video-avatar-absent-content">
{isAvatarUserCreator
? t("teacher-left-temporarily")
: avatarUser
? t("user-left-temporarily", { name: avatarUser.name })
: t("student-left-temporarily")}
{isAvatarUserCreator ? (
t("teacher-left-temporarily")
) : avatarUser ? (
<>
<span className="video-avatar-absent-name">{avatarUser.name}</span>
<span className="video-avatar-absent-desc">
{t("user-left-temporarily")}
</span>
</>
) : (
t("student-left-temporarily")
)}
</span>
</div>
{absentView && portal && createPortal(absentView, portal)}
</div>
) : (
absentView
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ const Row = /* @__PURE__ */ observer(function Row({
<span className="users-panel-list-name-content">{user.name}</span>
{isSelf && <span className="users-panel-is-self">{t("me")}</span>}
</span>
<span className="users-panel-list-has-left">{t("offline")}</span>
<span className="users-panel-list-has-left">{t("has-left")}</span>
</div>
) : (
<span className="users-panel-list-name">
Expand Down
4 changes: 2 additions & 2 deletions packages/flat-i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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": {
Expand Down
4 changes: 2 additions & 2 deletions packages/flat-i18n/locales/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"during-the-presentation": "(发言中)",
"end": "结束",
"raised-hand": "举手",
"has-left": "已离开",
"has-left": "已离开",
"offline": "已离线",
"no-students": "暂无学生",
"no-one-raising-hand": "暂无学生举手",
Expand All @@ -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": "延迟:",
Expand Down
6 changes: 6 additions & 0 deletions packages/flat-pages/src/components/RTCAvatar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,13 @@ export const RTCAvatar: FC<RTCAvatarProps> = /* @__PURE__ */ observer<RTCAvatarP
<VideoAvatarAbsent
avatarUser={avatarUser}
isAvatarUserCreator={isAvatarUserCreator}
isCreator={isCreator}
isDropTarget={isDropTarget}
portal={avatarUser && getPortal(avatarUser.userUUID)}
small={small}
onDoubleClick={onDoubleClick}
onDragEnd={onDragEnd}
onDragStart={onDragStart}
/>
);
},
Expand Down
5 changes: 1 addition & 4 deletions packages/flat-pages/src/components/UserWindows.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,7 @@ export const UserWindows = observer<UserWindowsProps>(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) {
Expand Down Expand Up @@ -276,7 +274,6 @@ const UserAvatarWindow = observer<UserAvatarWindowProps>(function UserAvatarWind
return (
<AvatarWindow
key={userUUID}
hidden={classroom.userHasLeft(userUUID)}
mode={mode}
readonly={readonly}
rect={rect}
Expand Down