Add user list component + snap to user functionality (#1749)

This commit is contained in:
Oliver Benns 2020-06-19 11:36:49 +01:00 committed by GitHub
parent 8f65e37dac
commit ca87ca6fe9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 333 additions and 32 deletions

View file

@ -0,0 +1,14 @@
@import "../css/_variables";
.Avatar {
width: 2.5rem;
height: 2.5rem;
border-radius: 1.25rem;
display: flex;
justify-content: center;
align-items: center;
color: $oc-white;
cursor: pointer;
font-size: 0.8rem;
font-weight: 500;
}

25
src/components/Avatar.tsx Normal file
View file

@ -0,0 +1,25 @@
import "./Avatar.scss";
import React from "react";
type AvatarProps = {
children: string;
className?: string;
onClick: (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => void;
color: string;
};
export const Avatar = ({
children,
className,
color,
onClick,
}: AvatarProps) => (
<div
className={`Avatar ${className}`}
style={{ background: color }}
onClick={onClick}
>
{children}
</div>
);

View file

@ -10,6 +10,7 @@ import { ActionManager } from "../actions/manager";
import { Island } from "./Island";
import Stack from "./Stack";
import { FixedSideContainer } from "./FixedSideContainer";
import { UserList } from "./UserList";
import { LockIcon } from "./LockIcon";
import { ExportDialog, ExportCB } from "./ExportDialog";
import { LanguageList } from "./LanguageList";
@ -28,6 +29,7 @@ import { LoadingMessage } from "./LoadingMessage";
import { CLASSES } from "../constants";
import { shield } from "./icons";
import { GitHubCorner } from "./GitHubCorner";
import { Tooltip } from "./Tooltip";
import "./LayerUI.scss";
@ -61,6 +63,7 @@ const LayerUI = ({
}: LayerUIProps) => {
const isMobile = useIsMobile();
// TODO: Extend tooltip component and use here.
const renderEncryptedIcon = () => (
<a
className={`encrypted-icon tooltip zen-mode-visibility ${
@ -203,7 +206,23 @@ const LayerUI = ({
</Stack.Col>
)}
</Section>
<div />
<UserList
className={`zen-mode-transition ${
zenModeEnabled && "transition-right"
}`}
>
{Array.from(appState.collaborators)
// Collaborator is either not initialized or is actually the current user.
.filter(([_, client]) => Object.keys(client).length !== 0)
.map(([clientId, client]) => (
<Tooltip
label={client.username || "Unknown user"}
key={clientId}
>
{actionManager.renderAction("goToCollaborator", clientId)}
</Tooltip>
))}
</UserList>
</div>
{
<div

View file

@ -16,6 +16,7 @@ import { RoomDialog } from "./RoomDialog";
import { SCROLLBAR_WIDTH, SCROLLBAR_MARGIN } from "../scene/scrollbars";
import { LockIcon } from "./LockIcon";
import { LoadingMessage } from "./LoadingMessage";
import { UserList } from "./UserList";
type MobileMenuProps = {
appState: AppState;
@ -105,6 +106,22 @@ export const MobileMenu = ({
}}
/>
</fieldset>
<fieldset>
<legend>{t("labels.collaborators")}</legend>
<UserList mobile>
{Array.from(appState.collaborators)
// Collaborator is either not initialized or is actually the current user.
.filter(([_, client]) => Object.keys(client).length !== 0)
.map(([clientId, client]) => (
<React.Fragment key={clientId}>
{actionManager.renderAction(
"goToCollaborator",
clientId,
)}
</React.Fragment>
))}
</UserList>
</fieldset>
</Stack.Col>
</div>
</Section>

View file

@ -0,0 +1,48 @@
@import "../css/_variables";
.Tooltip {
position: relative;
}
.Tooltip__label {
--arrow-size: 4px;
visibility: hidden;
width: 10ch;
background: $oc-black;
color: $oc-white;
text-align: center;
border-radius: 4px;
padding: 4px;
position: absolute;
z-index: 10;
font-size: 0.7rem;
line-height: 1.5;
top: calc(100% + var(--arrow-size) + 3px);
// extra pixel offset for unknown reasons
left: calc(-50% + var(--arrow-size) / 2 - 1px);
word-wrap: break-word;
&::after {
content: "";
border: var(--arrow-size) solid transparent;
border-bottom-color: $oc-black;
position: absolute;
bottom: 100%;
left: calc(50% - var(--arrow-size));
}
}
// the following 3 rules ensure that the tooltip doesn't show (nor affect
// the cursor) when you drag over when you draw on canvas, but at the same
// time it still works when clicking on the link/shield
body:active .Tooltip:not(:hover) {
pointer-events: none;
}
body:not(:active) .Tooltip:hover .Tooltip__label {
visibility: visible;
}
.Tooltip__label:hover {
visibility: visible;
}

View file

@ -0,0 +1,15 @@
import "./Tooltip.scss";
import React from "react";
type TooltipProps = {
children: React.ReactNode;
label: string;
};
export const Tooltip = ({ children, label }: TooltipProps) => (
<div className="Tooltip">
<span className="Tooltip__label">{label}</span>
{children}
</div>
);

View file

@ -0,0 +1,22 @@
.UserList {
pointer-events: none;
/*github corner*/
padding: var(--space-factor) 40px var(--space-factor) var(--space-factor);
display: flex;
flex-wrap: wrap;
justify-content: flex-end;
}
.UserList > * {
pointer-events: all;
margin: 0 0 var(--space-factor) var(--space-factor);
}
.UserList_mobile {
padding: 0;
justify-content: normal;
}
.UserList_mobile > * {
margin: 0 var(--space-factor) var(--space-factor) 0;
}

View file

@ -0,0 +1,23 @@
import "./UserList.css";
import React from "react";
type UserListProps = {
children: React.ReactNode;
className?: string;
mobile?: boolean;
};
export const UserList = ({ children, className, mobile }: UserListProps) => {
let compClassName = "UserList";
if (className) {
compClassName += ` ${className}`;
}
if (mobile) {
compClassName += " UserList_mobile";
}
return <div className={compClassName}>{children}</div>;
};