aboutsummaryrefslogtreecommitdiffstats
path: root/packages/excalidraw/actions/actionNavigate.tsx
blob: 48037200cdd26289106667a7604fd3567693b5cd (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
import { getClientColor } from "../clients";
import { Avatar } from "../components/Avatar";
import type { GoToCollaboratorComponentProps } from "../components/UserList";
import {
  eyeIcon,
  microphoneIcon,
  microphoneMutedIcon,
} from "../components/icons";
import { t } from "../i18n";
import { CaptureUpdateAction } from "../store";
import type { Collaborator } from "../types";
import { register } from "./register";
import clsx from "clsx";

export const actionGoToCollaborator = register({
  name: "goToCollaborator",
  label: "Go to a collaborator",
  viewMode: true,
  trackEvent: { category: "collab" },
  perform: (_elements, appState, collaborator: Collaborator) => {
    if (
      !collaborator.socketId ||
      appState.userToFollow?.socketId === collaborator.socketId ||
      collaborator.isCurrentUser
    ) {
      return {
        appState: {
          ...appState,
          userToFollow: null,
        },
        captureUpdate: CaptureUpdateAction.EVENTUALLY,
      };
    }

    return {
      appState: {
        ...appState,
        userToFollow: {
          socketId: collaborator.socketId,
          username: collaborator.username || "",
        },
        // Close mobile menu
        openMenu: appState.openMenu === "canvas" ? null : appState.openMenu,
      },
      captureUpdate: CaptureUpdateAction.EVENTUALLY,
    };
  },
  PanelComponent: ({ updateData, data, appState }) => {
    const { socketId, collaborator, withName, isBeingFollowed } =
      data as GoToCollaboratorComponentProps;

    const background = getClientColor(socketId, collaborator);

    const statusClassNames = clsx({
      "is-followed": isBeingFollowed,
      "is-current-user": collaborator.isCurrentUser === true,
      "is-speaking": collaborator.isSpeaking,
      "is-in-call": collaborator.isInCall,
      "is-muted": collaborator.isMuted,
    });

    const statusIconJSX = collaborator.isInCall ? (
      collaborator.isSpeaking ? (
        <div
          className="UserList__collaborator-status-icon-speaking-indicator"
          title={t("userList.hint.isSpeaking")}
        >
          <div />
          <div />
          <div />
        </div>
      ) : collaborator.isMuted ? (
        <div
          className="UserList__collaborator-status-icon-microphone-muted"
          title={t("userList.hint.micMuted")}
        >
          {microphoneMutedIcon}
        </div>
      ) : (
        <div title={t("userList.hint.inCall")}>{microphoneIcon}</div>
      )
    ) : null;

    return withName ? (
      <div
        className={`dropdown-menu-item dropdown-menu-item-base UserList__collaborator ${statusClassNames}`}
        style={{ [`--avatar-size` as any]: "1.5rem" }}
        onClick={() => updateData<Collaborator>(collaborator)}
      >
        <Avatar
          color={background}
          onClick={() => {}}
          name={collaborator.username || ""}
          src={collaborator.avatarUrl}
          className={statusClassNames}
        />
        <div className="UserList__collaborator-name">
          {collaborator.username}
        </div>
        <div className="UserList__collaborator-status-icons" aria-hidden>
          {isBeingFollowed && (
            <div
              className="UserList__collaborator-status-icon-is-followed"
              title={t("userList.hint.followStatus")}
            >
              {eyeIcon}
            </div>
          )}
          {statusIconJSX}
        </div>
      </div>
    ) : (
      <div
        className={`UserList__collaborator UserList__collaborator--avatar-only ${statusClassNames}`}
      >
        <Avatar
          color={background}
          onClick={() => {
            updateData(collaborator);
          }}
          name={collaborator.username || ""}
          src={collaborator.avatarUrl}
          className={statusClassNames}
        />
        {statusIconJSX && (
          <div className="UserList__collaborator-status-icon">
            {statusIconJSX}
          </div>
        )}
      </div>
    );
  },
});