Home page styling
This commit is contained in:
		
					parent
					
						
							
								9c7006f239
							
						
					
				
			
			
				commit
				
					
						20350e66a2
					
				
			
		
					 13 changed files with 467 additions and 216 deletions
				
			
		
							
								
								
									
										58
									
								
								src/Avatar.jsx
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								src/Avatar.jsx
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,58 @@
 | 
				
			||||||
 | 
					import React, { useMemo } from "react";
 | 
				
			||||||
 | 
					import classNames from "classnames";
 | 
				
			||||||
 | 
					import styles from "./Avatar.module.css";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const backgroundColors = [
 | 
				
			||||||
 | 
					  "#5C56F5",
 | 
				
			||||||
 | 
					  "#03B381",
 | 
				
			||||||
 | 
					  "#368BD6",
 | 
				
			||||||
 | 
					  "#AC3BA8",
 | 
				
			||||||
 | 
					  "#E64F7A",
 | 
				
			||||||
 | 
					  "#FF812D",
 | 
				
			||||||
 | 
					  "#2DC2C5",
 | 
				
			||||||
 | 
					  "#74D12C",
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function hashStringToArrIndex(str, arrLength) {
 | 
				
			||||||
 | 
					  let sum = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for (let i = 0; i < str.length; i++) {
 | 
				
			||||||
 | 
					    sum += str.charCodeAt(i);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return sum % arrLength;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function Avatar({
 | 
				
			||||||
 | 
					  bgKey,
 | 
				
			||||||
 | 
					  src,
 | 
				
			||||||
 | 
					  fallback,
 | 
				
			||||||
 | 
					  size,
 | 
				
			||||||
 | 
					  className,
 | 
				
			||||||
 | 
					  style,
 | 
				
			||||||
 | 
					  ...rest
 | 
				
			||||||
 | 
					}) {
 | 
				
			||||||
 | 
					  const backgroundColor = useMemo(() => {
 | 
				
			||||||
 | 
					    const index = hashStringToArrIndex(
 | 
				
			||||||
 | 
					      bgKey || fallback || src,
 | 
				
			||||||
 | 
					      backgroundColors.length
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    return backgroundColors[index];
 | 
				
			||||||
 | 
					  }, [bgKey, src, fallback]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div
 | 
				
			||||||
 | 
					      className={classNames(styles.avatar, styles[size || "md"], className)}
 | 
				
			||||||
 | 
					      style={{ backgroundColor, ...style }}
 | 
				
			||||||
 | 
					      {...rest}
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      {src ? (
 | 
				
			||||||
 | 
					        <img src={src} />
 | 
				
			||||||
 | 
					      ) : typeof fallback === "string" ? (
 | 
				
			||||||
 | 
					        <span>{fallback}</span>
 | 
				
			||||||
 | 
					      ) : (
 | 
				
			||||||
 | 
					        fallback
 | 
				
			||||||
 | 
					      )}
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										46
									
								
								src/Avatar.module.css
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/Avatar.module.css
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,46 @@
 | 
				
			||||||
 | 
					.avatar {
 | 
				
			||||||
 | 
					  position: relative;
 | 
				
			||||||
 | 
					  color: #ffffff;
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					  justify-content: center;
 | 
				
			||||||
 | 
					  pointer-events: none;
 | 
				
			||||||
 | 
					  font-weight: 600;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.avatar img {
 | 
				
			||||||
 | 
					  width: 100%;
 | 
				
			||||||
 | 
					  height: 100%;
 | 
				
			||||||
 | 
					  object-fit: cover;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.avatar svg * {
 | 
				
			||||||
 | 
					  fill: #ffffff;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.sm {
 | 
				
			||||||
 | 
					  width: 22px;
 | 
				
			||||||
 | 
					  height: 22px;
 | 
				
			||||||
 | 
					  border-radius: 22px;
 | 
				
			||||||
 | 
					  font-size: 14px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.md {
 | 
				
			||||||
 | 
					  width: 36px;
 | 
				
			||||||
 | 
					  height: 36px;
 | 
				
			||||||
 | 
					  border-radius: 36px;
 | 
				
			||||||
 | 
					  font-size: 20px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.lg {
 | 
				
			||||||
 | 
					  width: 42px;
 | 
				
			||||||
 | 
					  height: 42px;
 | 
				
			||||||
 | 
					  border-radius: 42px;
 | 
				
			||||||
 | 
					  font-size: 36px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.xl {
 | 
				
			||||||
 | 
					  width: 90px;
 | 
				
			||||||
 | 
					  height: 90px;
 | 
				
			||||||
 | 
					  border-radius: 90px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										31
									
								
								src/CallTile.jsx
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								src/CallTile.jsx
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,31 @@
 | 
				
			||||||
 | 
					import React from "react";
 | 
				
			||||||
 | 
					import { Link } from "react-router-dom";
 | 
				
			||||||
 | 
					import { CopyButton } from "./button";
 | 
				
			||||||
 | 
					import { Facepile } from "./Facepile";
 | 
				
			||||||
 | 
					import { Avatar } from "./Avatar";
 | 
				
			||||||
 | 
					import { ReactComponent as VideoIcon } from "./icons/Video.svg";
 | 
				
			||||||
 | 
					import styles from "./CallTile.module.css";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function CallTile({ name, avatarUrl, roomUrl, participants }) {
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <Link to={roomUrl} className={styles.callTile}>
 | 
				
			||||||
 | 
					      <Avatar
 | 
				
			||||||
 | 
					        size="md"
 | 
				
			||||||
 | 
					        bgKey={name}
 | 
				
			||||||
 | 
					        src={avatarUrl}
 | 
				
			||||||
 | 
					        fallback={<VideoIcon width={16} height={16} />}
 | 
				
			||||||
 | 
					        className={styles.avatar}
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					      <div className={styles.callInfo}>
 | 
				
			||||||
 | 
					        <h5>{name}</h5>
 | 
				
			||||||
 | 
					        <p>{roomUrl}</p>
 | 
				
			||||||
 | 
					        {participants && <Facepile participants={participants} />}
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <CopyButton
 | 
				
			||||||
 | 
					        className={styles.copyButton}
 | 
				
			||||||
 | 
					        variant="icon"
 | 
				
			||||||
 | 
					        value={roomUrl}
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					    </Link>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										54
									
								
								src/CallTile.module.css
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								src/CallTile.module.css
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,54 @@
 | 
				
			||||||
 | 
					.callTile {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  width: 329px;
 | 
				
			||||||
 | 
					  height: 94px;
 | 
				
			||||||
 | 
					  padding: 12px;
 | 
				
			||||||
 | 
					  text-decoration: none;
 | 
				
			||||||
 | 
					  background-color: var(--bgColor2);
 | 
				
			||||||
 | 
					  border-radius: 8px;
 | 
				
			||||||
 | 
					  overflow: hidden;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.avatar,
 | 
				
			||||||
 | 
					.copyButton {
 | 
				
			||||||
 | 
					  flex-shrink: 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.callInfo {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  flex-direction: column;
 | 
				
			||||||
 | 
					  flex: 1;
 | 
				
			||||||
 | 
					  padding: 0 16px;
 | 
				
			||||||
 | 
					  color: var(--textColor1);
 | 
				
			||||||
 | 
					  min-width: 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.callInfo > * {
 | 
				
			||||||
 | 
					  margin-top: 0;
 | 
				
			||||||
 | 
					  margin-bottom: 8px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.callInfo > :last-child {
 | 
				
			||||||
 | 
					  margin-bottom: 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.callInfo h5 {
 | 
				
			||||||
 | 
					  font-size: 15px;
 | 
				
			||||||
 | 
					  font-weight: 600;
 | 
				
			||||||
 | 
					  overflow: hidden;
 | 
				
			||||||
 | 
					  text-overflow: ellipsis;
 | 
				
			||||||
 | 
					  white-space: nowrap;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.callInfo p {
 | 
				
			||||||
 | 
					  font-weight: 400;
 | 
				
			||||||
 | 
					  font-size: 12px;
 | 
				
			||||||
 | 
					  overflow: hidden;
 | 
				
			||||||
 | 
					  text-overflow: ellipsis;
 | 
				
			||||||
 | 
					  white-space: nowrap;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.copyButton {
 | 
				
			||||||
 | 
					  width: 16px;
 | 
				
			||||||
 | 
					  height: 16px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,32 +1,32 @@
 | 
				
			||||||
import React from "react";
 | 
					import React from "react";
 | 
				
			||||||
import styles from "./Facepile.module.css";
 | 
					import styles from "./Facepile.module.css";
 | 
				
			||||||
import ColorHash from "color-hash";
 | 
					 | 
				
			||||||
import classNames from "classnames";
 | 
					import classNames from "classnames";
 | 
				
			||||||
 | 
					import { Avatar } from "./Avatar";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const colorHash = new ColorHash({ lightness: 0.3 });
 | 
					export function Facepile({ className, participants, ...rest }) {
 | 
				
			||||||
 | 
					 | 
				
			||||||
export function Facepile({ participants }) {
 | 
					 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <div
 | 
					    <div
 | 
				
			||||||
      className={styles.facepile}
 | 
					      className={classNames(styles.facepile, className)}
 | 
				
			||||||
      title={participants.map((member) => member.name).join(", ")}
 | 
					      title={participants.map((member) => member.name).join(", ")}
 | 
				
			||||||
 | 
					      {...rest}
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
      {participants.slice(0, 3).map((member) => (
 | 
					      {participants.slice(0, 3).map((member, i) => (
 | 
				
			||||||
        <div
 | 
					        <Avatar
 | 
				
			||||||
          key={member.userId}
 | 
					          key={member.userId}
 | 
				
			||||||
 | 
					          size="sm"
 | 
				
			||||||
 | 
					          fallback={member.name.slice(0, 1).toUpperCase()}
 | 
				
			||||||
          className={styles.avatar}
 | 
					          className={styles.avatar}
 | 
				
			||||||
          style={{ backgroundColor: colorHash.hex(member.name) }}
 | 
					          style={{ left: i * 22 }}
 | 
				
			||||||
        >
 | 
					        />
 | 
				
			||||||
          <span>{member.name.slice(0, 1).toUpperCase()}</span>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
      ))}
 | 
					      ))}
 | 
				
			||||||
      {participants.length > 3 && (
 | 
					      {participants.length > 3 && (
 | 
				
			||||||
        <div
 | 
					        <Avatar
 | 
				
			||||||
          key="additional"
 | 
					          key="additional"
 | 
				
			||||||
          className={classNames(styles.avatar, styles.additional)}
 | 
					          size="sm"
 | 
				
			||||||
        >
 | 
					          fallback={`+${participants.length - 3}`}
 | 
				
			||||||
          <span>{`+${participants.length - 3}`}</span>
 | 
					          className={styles.avatar}
 | 
				
			||||||
        </div>
 | 
					          style={{ left: 3 * 22 }}
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
      )}
 | 
					      )}
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,31 +1,11 @@
 | 
				
			||||||
.facepile {
 | 
					.facepile {
 | 
				
			||||||
  display: flex;
 | 
					  width: 100%;
 | 
				
			||||||
  margin: 0 16px;
 | 
					  height: 24px;
 | 
				
			||||||
 | 
					  position: relative;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.facepile .avatar {
 | 
					.facepile .avatar {
 | 
				
			||||||
  position: relative;
 | 
					 | 
				
			||||||
  width: 20px;
 | 
					 | 
				
			||||||
  height: 20px;
 | 
					 | 
				
			||||||
  border-radius: 20px;
 | 
					 | 
				
			||||||
  background-color: var(--primaryColor);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.facepile .avatar > * {
 | 
					 | 
				
			||||||
  position: absolute;
 | 
					  position: absolute;
 | 
				
			||||||
  left: 0;
 | 
					  top: 0;
 | 
				
			||||||
  color: #fff;
 | 
					  border: 1px solid var(--bgColor2);
 | 
				
			||||||
  text-align: center;
 | 
					 | 
				
			||||||
  pointer-events: none;
 | 
					 | 
				
			||||||
  font-weight: 600;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.facepile .avatar span {
 | 
					 | 
				
			||||||
  font-size: 14px;
 | 
					 | 
				
			||||||
  width: 20px;
 | 
					 | 
				
			||||||
  line-height: 20px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.facepile .avatar.additional span {
 | 
					 | 
				
			||||||
  font-size: 12px;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										163
									
								
								src/Home.jsx
									
										
									
									
									
								
							
							
						
						
									
										163
									
								
								src/Home.jsx
									
										
									
									
									
								
							| 
						 | 
					@ -15,25 +15,21 @@ limitations under the License.
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import React, { useCallback, useState } from "react";
 | 
					import React, { useCallback, useState } from "react";
 | 
				
			||||||
import { useHistory, Link } from "react-router-dom";
 | 
					import { useHistory } from "react-router-dom";
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  useGroupCallRooms,
 | 
					  useGroupCallRooms,
 | 
				
			||||||
  usePublicRooms,
 | 
					  usePublicRooms,
 | 
				
			||||||
} from "./ConferenceCallManagerHooks";
 | 
					} from "./ConferenceCallManagerHooks";
 | 
				
			||||||
import { Header, HeaderLogo, LeftNav, RightNav } from "./Header";
 | 
					import { Header, HeaderLogo, LeftNav, RightNav } from "./Header";
 | 
				
			||||||
import ColorHash from "color-hash";
 | 
					 | 
				
			||||||
import styles from "./Home.module.css";
 | 
					import styles from "./Home.module.css";
 | 
				
			||||||
import { FieldRow, InputField, ErrorMessage } from "./Input";
 | 
					import { FieldRow, InputField, ErrorMessage } from "./Input";
 | 
				
			||||||
import { Center, Content, Modal } from "./Layout";
 | 
					 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  GroupCallIntent,
 | 
					  GroupCallIntent,
 | 
				
			||||||
  GroupCallType,
 | 
					  GroupCallType,
 | 
				
			||||||
} from "matrix-js-sdk/src/browser-index";
 | 
					} from "matrix-js-sdk/src/browser-index";
 | 
				
			||||||
import { Facepile } from "./Facepile";
 | 
					 | 
				
			||||||
import { UserMenu } from "./UserMenu";
 | 
					import { UserMenu } from "./UserMenu";
 | 
				
			||||||
import { Button } from "./button";
 | 
					import { Button } from "./button";
 | 
				
			||||||
 | 
					import { CallTile } from "./CallTile";
 | 
				
			||||||
const colorHash = new ColorHash({ lightness: 0.3 });
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
function roomAliasFromRoomName(roomName) {
 | 
					function roomAliasFromRoomName(roomName) {
 | 
				
			||||||
  return roomName
 | 
					  return roomName
 | 
				
			||||||
| 
						 | 
					@ -46,10 +42,8 @@ function roomAliasFromRoomName(roomName) {
 | 
				
			||||||
export function Home({ client, onLogout }) {
 | 
					export function Home({ client, onLogout }) {
 | 
				
			||||||
  const history = useHistory();
 | 
					  const history = useHistory();
 | 
				
			||||||
  const [roomName, setRoomName] = useState("");
 | 
					  const [roomName, setRoomName] = useState("");
 | 
				
			||||||
  const [roomAlias, setRoomAlias] = useState("");
 | 
					 | 
				
			||||||
  const [guestAccess, setGuestAccess] = useState(false);
 | 
					  const [guestAccess, setGuestAccess] = useState(false);
 | 
				
			||||||
  const [createRoomError, setCreateRoomError] = useState();
 | 
					  const [createRoomError, setCreateRoomError] = useState();
 | 
				
			||||||
  const [showAdvanced, setShowAdvanced] = useState();
 | 
					 | 
				
			||||||
  const rooms = useGroupCallRooms(client);
 | 
					  const rooms = useGroupCallRooms(client);
 | 
				
			||||||
  const publicRooms = usePublicRooms(
 | 
					  const publicRooms = usePublicRooms(
 | 
				
			||||||
    client,
 | 
					    client,
 | 
				
			||||||
| 
						 | 
					@ -110,38 +104,65 @@ export function Home({ client, onLogout }) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      const data = new FormData(e.target);
 | 
					      const data = new FormData(e.target);
 | 
				
			||||||
      const roomName = data.get("roomName");
 | 
					      const roomName = data.get("roomName");
 | 
				
			||||||
      const roomAlias = data.get("roomAlias");
 | 
					 | 
				
			||||||
      const guestAccess = data.get("guestAccess");
 | 
					      const guestAccess = data.get("guestAccess");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      createRoom(roomName, roomAlias, guestAccess).catch((error) => {
 | 
					      createRoom(roomName, roomAliasFromRoomName(roomName), guestAccess).catch(
 | 
				
			||||||
 | 
					        (error) => {
 | 
				
			||||||
          setCreateRoomError(error);
 | 
					          setCreateRoomError(error);
 | 
				
			||||||
          setShowAdvanced(true);
 | 
					          setShowAdvanced(true);
 | 
				
			||||||
      });
 | 
					        }
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    [client]
 | 
					    [client]
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const [roomId, setRoomId] = useState("");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const onJoinRoom = useCallback(
 | 
				
			||||||
 | 
					    (e) => {
 | 
				
			||||||
 | 
					      e.preventDefault();
 | 
				
			||||||
 | 
					      const data = new FormData(e.target);
 | 
				
			||||||
 | 
					      const roomId = data.get("roomId");
 | 
				
			||||||
 | 
					      history.push(`/room/${roomId}`);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    [history]
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <>
 | 
					    <div class={styles.home}>
 | 
				
			||||||
 | 
					      <div className={styles.left}>
 | 
				
			||||||
        <Header>
 | 
					        <Header>
 | 
				
			||||||
          <LeftNav>
 | 
					          <LeftNav>
 | 
				
			||||||
            <HeaderLogo />
 | 
					            <HeaderLogo />
 | 
				
			||||||
          </LeftNav>
 | 
					          </LeftNav>
 | 
				
			||||||
        <RightNav>
 | 
					 | 
				
			||||||
          <UserMenu
 | 
					 | 
				
			||||||
            signedIn
 | 
					 | 
				
			||||||
            userName={client.getUserIdLocalpart()}
 | 
					 | 
				
			||||||
            onLogout={onLogout}
 | 
					 | 
				
			||||||
          />
 | 
					 | 
				
			||||||
        </RightNav>
 | 
					 | 
				
			||||||
        </Header>
 | 
					        </Header>
 | 
				
			||||||
      <Content>
 | 
					        <div className={styles.content}>
 | 
				
			||||||
        <Center>
 | 
					          <div className={styles.centered}>
 | 
				
			||||||
          <Modal>
 | 
					            <form onSubmit={onJoinRoom}>
 | 
				
			||||||
            <section>
 | 
					              <h1>Join a call</h1>
 | 
				
			||||||
 | 
					              <FieldRow className={styles.fieldRow}>
 | 
				
			||||||
 | 
					                <InputField
 | 
				
			||||||
 | 
					                  id="roomId"
 | 
				
			||||||
 | 
					                  name="roomId"
 | 
				
			||||||
 | 
					                  label="Call ID"
 | 
				
			||||||
 | 
					                  type="text"
 | 
				
			||||||
 | 
					                  required
 | 
				
			||||||
 | 
					                  autoComplete="off"
 | 
				
			||||||
 | 
					                  placeholder="Call ID"
 | 
				
			||||||
 | 
					                  value={roomId}
 | 
				
			||||||
 | 
					                  onChange={(e) => setRoomId(e.target.value)}
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
 | 
					              </FieldRow>
 | 
				
			||||||
 | 
					              <FieldRow className={styles.fieldRow}>
 | 
				
			||||||
 | 
					                <Button className={styles.button} type="submit">
 | 
				
			||||||
 | 
					                  Join call
 | 
				
			||||||
 | 
					                </Button>
 | 
				
			||||||
 | 
					              </FieldRow>
 | 
				
			||||||
 | 
					            </form>
 | 
				
			||||||
 | 
					            <hr />
 | 
				
			||||||
            <form onSubmit={onCreateRoom}>
 | 
					            <form onSubmit={onCreateRoom}>
 | 
				
			||||||
                <h2>Create New Room</h2>
 | 
					              <h1>Create a call</h1>
 | 
				
			||||||
                <FieldRow>
 | 
					              <FieldRow className={styles.fieldRow}>
 | 
				
			||||||
                <InputField
 | 
					                <InputField
 | 
				
			||||||
                  id="roomName"
 | 
					                  id="roomName"
 | 
				
			||||||
                  name="roomName"
 | 
					                  name="roomName"
 | 
				
			||||||
| 
						 | 
					@ -154,20 +175,6 @@ export function Home({ client, onLogout }) {
 | 
				
			||||||
                  onChange={(e) => setRoomName(e.target.value)}
 | 
					                  onChange={(e) => setRoomName(e.target.value)}
 | 
				
			||||||
                />
 | 
					                />
 | 
				
			||||||
              </FieldRow>
 | 
					              </FieldRow>
 | 
				
			||||||
                <details open={showAdvanced}>
 | 
					 | 
				
			||||||
                  <summary>Advanced</summary>
 | 
					 | 
				
			||||||
                  <FieldRow>
 | 
					 | 
				
			||||||
                    <InputField
 | 
					 | 
				
			||||||
                      id="roomAlias"
 | 
					 | 
				
			||||||
                      name="roomAlias"
 | 
					 | 
				
			||||||
                      label="Room Alias"
 | 
					 | 
				
			||||||
                      type="text"
 | 
					 | 
				
			||||||
                      autoComplete="off"
 | 
					 | 
				
			||||||
                      placeholder="Room Alias"
 | 
					 | 
				
			||||||
                      value={roomAlias || roomAliasFromRoomName(roomName)}
 | 
					 | 
				
			||||||
                      onChange={(e) => setRoomAlias(e.target.value)}
 | 
					 | 
				
			||||||
                    />
 | 
					 | 
				
			||||||
                  </FieldRow>
 | 
					 | 
				
			||||||
              <FieldRow>
 | 
					              <FieldRow>
 | 
				
			||||||
                <InputField
 | 
					                <InputField
 | 
				
			||||||
                  id="guestAccess"
 | 
					                  id="guestAccess"
 | 
				
			||||||
| 
						 | 
					@ -178,63 +185,61 @@ export function Home({ client, onLogout }) {
 | 
				
			||||||
                  onChange={(e) => setGuestAccess(e.target.checked)}
 | 
					                  onChange={(e) => setGuestAccess(e.target.checked)}
 | 
				
			||||||
                />
 | 
					                />
 | 
				
			||||||
              </FieldRow>
 | 
					              </FieldRow>
 | 
				
			||||||
                </details>
 | 
					 | 
				
			||||||
              {createRoomError && (
 | 
					              {createRoomError && (
 | 
				
			||||||
                  <FieldRow>
 | 
					                <FieldRow className={styles.fieldRow}>
 | 
				
			||||||
                  <ErrorMessage>{createRoomError.message}</ErrorMessage>
 | 
					                  <ErrorMessage>{createRoomError.message}</ErrorMessage>
 | 
				
			||||||
                </FieldRow>
 | 
					                </FieldRow>
 | 
				
			||||||
              )}
 | 
					              )}
 | 
				
			||||||
                <FieldRow rightAlign>
 | 
					              <FieldRow className={styles.fieldRow}>
 | 
				
			||||||
                  <Button type="submit">Create Room</Button>
 | 
					                <Button className={styles.button} type="submit">
 | 
				
			||||||
 | 
					                  Create call
 | 
				
			||||||
 | 
					                </Button>
 | 
				
			||||||
              </FieldRow>
 | 
					              </FieldRow>
 | 
				
			||||||
            </form>
 | 
					            </form>
 | 
				
			||||||
            </section>
 | 
					          </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <div className={styles.right}>
 | 
				
			||||||
 | 
					        <Header>
 | 
				
			||||||
 | 
					          <LeftNav />
 | 
				
			||||||
 | 
					          <RightNav>
 | 
				
			||||||
 | 
					            <UserMenu
 | 
				
			||||||
 | 
					              signedIn
 | 
				
			||||||
 | 
					              userName={client.getUserIdLocalpart()}
 | 
				
			||||||
 | 
					              onLogout={onLogout}
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					          </RightNav>
 | 
				
			||||||
 | 
					        </Header>
 | 
				
			||||||
 | 
					        <div className={styles.content}>
 | 
				
			||||||
          {publicRooms.length > 0 && (
 | 
					          {publicRooms.length > 0 && (
 | 
				
			||||||
              <section>
 | 
					            <>
 | 
				
			||||||
                <h3>Public Rooms</h3>
 | 
					              <h3>Public Calls</h3>
 | 
				
			||||||
              <div className={styles.roomList}>
 | 
					              <div className={styles.roomList}>
 | 
				
			||||||
                {publicRooms.map((room) => (
 | 
					                {publicRooms.map((room) => (
 | 
				
			||||||
                    <Link
 | 
					                  <CallTile
 | 
				
			||||||
                      className={styles.roomListItem}
 | 
					 | 
				
			||||||
                    key={room.room_id}
 | 
					                    key={room.room_id}
 | 
				
			||||||
                      to={`/room/${room.room_id}`}
 | 
					                    name={room.name}
 | 
				
			||||||
                    >
 | 
					                    avatarUrl={null}
 | 
				
			||||||
                      <div
 | 
					                    roomUrl={`/room/${room.room_id}`}
 | 
				
			||||||
                        className={styles.roomAvatar}
 | 
					                  />
 | 
				
			||||||
                        style={{ backgroundColor: colorHash.hex(room.name) }}
 | 
					 | 
				
			||||||
                      >
 | 
					 | 
				
			||||||
                        <span>{room.name.slice(0, 1)}</span>
 | 
					 | 
				
			||||||
                      </div>
 | 
					 | 
				
			||||||
                      <div className={styles.roomName}>{room.name}</div>
 | 
					 | 
				
			||||||
                    </Link>
 | 
					 | 
				
			||||||
                ))}
 | 
					                ))}
 | 
				
			||||||
              </div>
 | 
					              </div>
 | 
				
			||||||
              </section>
 | 
					            </>
 | 
				
			||||||
          )}
 | 
					          )}
 | 
				
			||||||
            <section>
 | 
					          <h3>Recent Calls</h3>
 | 
				
			||||||
              <h3>Recent Rooms</h3>
 | 
					 | 
				
			||||||
          <div className={styles.roomList}>
 | 
					          <div className={styles.roomList}>
 | 
				
			||||||
            {rooms.map(({ room, participants }) => (
 | 
					            {rooms.map(({ room, participants }) => (
 | 
				
			||||||
                  <Link
 | 
					              <CallTile
 | 
				
			||||||
                    className={styles.roomListItem}
 | 
					 | 
				
			||||||
                key={room.roomId}
 | 
					                key={room.roomId}
 | 
				
			||||||
                    to={`/room/${room.getCanonicalAlias() || room.roomId}`}
 | 
					                name={room.name}
 | 
				
			||||||
                  >
 | 
					                avatarUrl={null}
 | 
				
			||||||
                    <div
 | 
					                roomUrl={`/room/${room.getCanonicalAlias() || room.roomId}`}
 | 
				
			||||||
                      className={styles.roomAvatar}
 | 
					                participants={participants}
 | 
				
			||||||
                      style={{ backgroundColor: colorHash.hex(room.name) }}
 | 
					              />
 | 
				
			||||||
                    >
 | 
					 | 
				
			||||||
                      <span>{room.name.slice(0, 1)}</span>
 | 
					 | 
				
			||||||
                    </div>
 | 
					 | 
				
			||||||
                    <div className={styles.roomName}>{room.name}</div>
 | 
					 | 
				
			||||||
                    <Facepile participants={participants} />
 | 
					 | 
				
			||||||
                  </Link>
 | 
					 | 
				
			||||||
            ))}
 | 
					            ))}
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
            </section>
 | 
					        </div>
 | 
				
			||||||
          </Modal>
 | 
					      </div>
 | 
				
			||||||
        </Center>
 | 
					    </div>
 | 
				
			||||||
      </Content>
 | 
					 | 
				
			||||||
    </>
 | 
					 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,47 +1,109 @@
 | 
				
			||||||
.roomList {
 | 
					.home {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  flex: 1;
 | 
				
			||||||
 | 
					  height: 100%;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.roomListItem {
 | 
					.left,
 | 
				
			||||||
  margin-bottom: 4px;
 | 
					.right {
 | 
				
			||||||
  padding: 4px;
 | 
					 | 
				
			||||||
  display: flex;
 | 
					  display: flex;
 | 
				
			||||||
  cursor: pointer;
 | 
					  flex-direction: column;
 | 
				
			||||||
  text-decoration: none;
 | 
					  flex: 1;
 | 
				
			||||||
  color: var(--textColor1);
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.left {
 | 
				
			||||||
 | 
					  background-color: var(--bgColor2);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.centered {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  flex-direction: column;
 | 
				
			||||||
 | 
					  flex: 1;
 | 
				
			||||||
 | 
					  width: 100%;
 | 
				
			||||||
 | 
					  max-width: 512px;
 | 
				
			||||||
 | 
					  min-width: 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.content {
 | 
				
			||||||
 | 
					  flex: 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.left .content {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  flex-direction: column;
 | 
				
			||||||
 | 
					  padding-top: 113px;
 | 
				
			||||||
  align-items: center;
 | 
					  align-items: center;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.roomListItem:hover {
 | 
					.left .content form > * {
 | 
				
			||||||
  background-color: rgba(141, 151, 165, 0.2);
 | 
					  margin-top: 0;
 | 
				
			||||||
  border-radius: 8px;
 | 
					  margin-bottom: 24px;
 | 
				
			||||||
  color: var(--textColor1);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.roomAvatar {
 | 
					.left .content form > :last-child {
 | 
				
			||||||
  position: relative;
 | 
					  margin-bottom: 0;
 | 
				
			||||||
  width: 32px;
 | 
					 | 
				
			||||||
  height: 32px;
 | 
					 | 
				
			||||||
  border-radius: 32px;
 | 
					 | 
				
			||||||
  flex-shrink: 0;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.roomAvatar > * {
 | 
					.left .content hr {
 | 
				
			||||||
  position: absolute;
 | 
					  width: 100%;
 | 
				
			||||||
  left: 0;
 | 
					  border: none;
 | 
				
			||||||
  color: #fff;
 | 
					  border-top: 1px solid var(--bgColor4);
 | 
				
			||||||
 | 
					  color: var(--textColor2);
 | 
				
			||||||
 | 
					  overflow: visible;
 | 
				
			||||||
  text-align: center;
 | 
					  text-align: center;
 | 
				
			||||||
  pointer-events: none;
 | 
					  height: 5px;
 | 
				
			||||||
  font-weight: 400;
 | 
					  font-weight: 600;
 | 
				
			||||||
 | 
					  font-size: 15px;
 | 
				
			||||||
 | 
					  line-height: 24px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.roomAvatar span {
 | 
					.left .content hr:after {
 | 
				
			||||||
  font-size: 20.8px;
 | 
					  background-color: var(--bgColor2);
 | 
				
			||||||
  width: 32px;
 | 
					  content: "OR";
 | 
				
			||||||
  line-height: 32px;
 | 
					  padding: 0 12px;
 | 
				
			||||||
 | 
					  position: relative;
 | 
				
			||||||
 | 
					  top: -12px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.roomName {
 | 
					.left .content form {
 | 
				
			||||||
  margin-left: 8px;
 | 
					  display: flex;
 | 
				
			||||||
  font-size: 14px;
 | 
					  flex-direction: column;
 | 
				
			||||||
  line-height: 18px;
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					  padding: 92px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.fieldRow {
 | 
				
			||||||
 | 
					  width: 100%;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.button {
 | 
				
			||||||
 | 
					  height: 40px;
 | 
				
			||||||
 | 
					  width: 100%;
 | 
				
			||||||
 | 
					  font-size: 15px;
 | 
				
			||||||
 | 
					  font-weight: 600;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.left .content form:first-child {
 | 
				
			||||||
 | 
					  padding-top: 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.left .content form:last-child {
 | 
				
			||||||
 | 
					  padding-bottom: 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.right .content {
 | 
				
			||||||
 | 
					  padding: 113px 40px 40px 40px;
 | 
				
			||||||
 | 
					  overflow-y: auto;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.right .content h3:first-child {
 | 
				
			||||||
 | 
					  margin-top: 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.roomList {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  flex-wrap: wrap;
 | 
				
			||||||
 | 
					  justify-content: flex-start;
 | 
				
			||||||
 | 
					  gap: 24px;
 | 
				
			||||||
 | 
					  flex: 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,12 +35,12 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.inputField input {
 | 
					.inputField input {
 | 
				
			||||||
  font-weight: 400;
 | 
					  font-weight: 400;
 | 
				
			||||||
  font-size: 14px;
 | 
					  font-size: 15px;
 | 
				
			||||||
  border: none;
 | 
					  border: none;
 | 
				
			||||||
  border-radius: 4px;
 | 
					  border-radius: 4px;
 | 
				
			||||||
  padding: 8px 9px;
 | 
					  padding: 11px 9px;
 | 
				
			||||||
  color: var(--textColor1);
 | 
					  color: var(--textColor1);
 | 
				
			||||||
  background-color: var(--bgColor2);
 | 
					  background-color: var(--bgColor1);
 | 
				
			||||||
  flex: 1;
 | 
					  flex: 1;
 | 
				
			||||||
  min-width: 0;
 | 
					  min-width: 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -60,11 +60,11 @@
 | 
				
			||||||
    top 0.25s ease-out 0.1s, background-color 0.25s ease-out 0.1s;
 | 
					    top 0.25s ease-out 0.1s, background-color 0.25s ease-out 0.1s;
 | 
				
			||||||
  color: var(--textColor1);
 | 
					  color: var(--textColor1);
 | 
				
			||||||
  background-color: transparent;
 | 
					  background-color: transparent;
 | 
				
			||||||
  font-size: 14px;
 | 
					  font-size: 15px;
 | 
				
			||||||
  position: absolute;
 | 
					  position: absolute;
 | 
				
			||||||
  left: 0;
 | 
					  left: 0;
 | 
				
			||||||
  top: 0;
 | 
					  top: 0;
 | 
				
			||||||
  margin: 7px 8px;
 | 
					  margin: 9px 8px;
 | 
				
			||||||
  padding: 2px;
 | 
					  padding: 2px;
 | 
				
			||||||
  pointer-events: none;
 | 
					  pointer-events: none;
 | 
				
			||||||
  overflow: hidden;
 | 
					  overflow: hidden;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,6 +31,7 @@ import {
 | 
				
			||||||
  RightNav,
 | 
					  RightNav,
 | 
				
			||||||
  RoomHeaderInfo,
 | 
					  RoomHeaderInfo,
 | 
				
			||||||
  RoomSetupHeaderInfo,
 | 
					  RoomSetupHeaderInfo,
 | 
				
			||||||
 | 
					  HeaderLogo,
 | 
				
			||||||
} from "./Header";
 | 
					} from "./Header";
 | 
				
			||||||
import { GroupCallState } from "matrix-js-sdk/src/webrtc/groupCall";
 | 
					import { GroupCallState } from "matrix-js-sdk/src/webrtc/groupCall";
 | 
				
			||||||
import VideoGrid, {
 | 
					import VideoGrid, {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,7 +18,10 @@ const variantToClassName = {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const Button = forwardRef(
 | 
					export const Button = forwardRef(
 | 
				
			||||||
  ({ variant = "default", on, off, className, children, ...rest }, ref) => {
 | 
					  (
 | 
				
			||||||
 | 
					    { variant = "default", on, off, iconStyle, className, children, ...rest },
 | 
				
			||||||
 | 
					    ref
 | 
				
			||||||
 | 
					  ) => {
 | 
				
			||||||
    const buttonRef = useObjectRef(ref);
 | 
					    const buttonRef = useObjectRef(ref);
 | 
				
			||||||
    const { buttonProps } = useButton(rest, buttonRef);
 | 
					    const { buttonProps } = useButton(rest, buttonRef);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,10 +36,15 @@ export const Button = forwardRef(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <button
 | 
					      <button
 | 
				
			||||||
        className={classNames(variantToClassName[variant], className, {
 | 
					        className={classNames(
 | 
				
			||||||
 | 
					          variantToClassName[variant],
 | 
				
			||||||
 | 
					          styles[iconStyle],
 | 
				
			||||||
 | 
					          className,
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
            [styles.on]: on,
 | 
					            [styles.on]: on,
 | 
				
			||||||
            [styles.off]: off,
 | 
					            [styles.off]: off,
 | 
				
			||||||
        })}
 | 
					          }
 | 
				
			||||||
 | 
					        )}
 | 
				
			||||||
        {...filteredButtonProps}
 | 
					        {...filteredButtonProps}
 | 
				
			||||||
        ref={buttonRef}
 | 
					        ref={buttonRef}
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -52,22 +52,22 @@ limitations under the License.
 | 
				
			||||||
  background-color: #ffffff;
 | 
					  background-color: #ffffff;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.iconButton svg * {
 | 
					.iconButton:not(.stroke) svg * {
 | 
				
			||||||
  fill: #8e99a4;
 | 
					  fill: #8e99a4;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.iconButton:hover svg * {
 | 
					.iconButton:not(.stroke):hover svg * {
 | 
				
			||||||
  fill: #8d97a5;
 | 
					  fill: #8d97a5;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.iconButton:hover svg * {
 | 
					.iconButton.on:not(.stroke) svg * {
 | 
				
			||||||
  fill: #8d97a5;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.iconButton.on svg * {
 | 
					 | 
				
			||||||
  fill: #0dbd8b;
 | 
					  fill: #0dbd8b;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.iconButton.on.stroke svg * {
 | 
				
			||||||
 | 
					  stroke: #0dbd8b;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.hangupButton,
 | 
					.hangupButton,
 | 
				
			||||||
.hangupButton:hover {
 | 
					.hangupButton:hover {
 | 
				
			||||||
  background-color: #ff5b55;
 | 
					  background-color: #ff5b55;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,19 +4,25 @@ import { ReactComponent as CheckIcon } from "../icons/Check.svg";
 | 
				
			||||||
import { ReactComponent as CopyIcon } from "../icons/Copy.svg";
 | 
					import { ReactComponent as CopyIcon } from "../icons/Copy.svg";
 | 
				
			||||||
import { Button } from "./Button";
 | 
					import { Button } from "./Button";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function CopyButton({ value, children, ...rest }) {
 | 
					export function CopyButton({ value, children, variant, ...rest }) {
 | 
				
			||||||
  const [isCopied, setCopied] = useClipboard(value, { successDuration: 3000 });
 | 
					  const [isCopied, setCopied] = useClipboard(value, { successDuration: 3000 });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <Button {...rest} variant="copy" on={isCopied} onPress={setCopied}>
 | 
					    <Button
 | 
				
			||||||
 | 
					      {...rest}
 | 
				
			||||||
 | 
					      variant={variant || "copy"}
 | 
				
			||||||
 | 
					      on={isCopied}
 | 
				
			||||||
 | 
					      onPress={setCopied}
 | 
				
			||||||
 | 
					      iconStyle={isCopied ? "stroke" : "fill"}
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
      {isCopied ? (
 | 
					      {isCopied ? (
 | 
				
			||||||
        <>
 | 
					        <>
 | 
				
			||||||
          <span>Copied!</span>
 | 
					          {variant !== "icon" && <span>Copied!</span>}
 | 
				
			||||||
          <CheckIcon />
 | 
					          <CheckIcon />
 | 
				
			||||||
        </>
 | 
					        </>
 | 
				
			||||||
      ) : (
 | 
					      ) : (
 | 
				
			||||||
        <>
 | 
					        <>
 | 
				
			||||||
          <span>{children || value}</span>
 | 
					          {variant !== "icon" && <span>{children || value}</span>}
 | 
				
			||||||
          <CopyIcon />
 | 
					          <CopyIcon />
 | 
				
			||||||
        </>
 | 
					        </>
 | 
				
			||||||
      )}
 | 
					      )}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue