Update header styling
This commit is contained in:
parent
dbaf467a20
commit
f09454ec09
13 changed files with 316 additions and 110 deletions
|
@ -67,7 +67,7 @@ export default function App() {
|
||||||
</SentryRoute>
|
</SentryRoute>
|
||||||
<SentryRoute path="/room/:roomId?">
|
<SentryRoute path="/room/:roomId?">
|
||||||
{authenticated ? (
|
{authenticated ? (
|
||||||
<Room client={client} />
|
<Room client={client} onLogout={logout} />
|
||||||
) : (
|
) : (
|
||||||
<GuestAuthPage onLoginAsGuest={registerGuest} />
|
<GuestAuthPage onLoginAsGuest={registerGuest} />
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -249,8 +249,8 @@ export function useClient(homeserverUrl) {
|
||||||
|
|
||||||
const logout = useCallback(() => {
|
const logout = useCallback(() => {
|
||||||
localStorage.removeItem("matrix-auth-store");
|
localStorage.removeItem("matrix-auth-store");
|
||||||
setState({ client: undefined, loading: false, authenticated: false });
|
window.location = "/";
|
||||||
}, []);
|
}, [history]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
loading,
|
loading,
|
||||||
|
|
|
@ -17,7 +17,7 @@ limitations under the License.
|
||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import styles from "./GuestAuthPage.module.css";
|
import styles from "./GuestAuthPage.module.css";
|
||||||
import { useLocation, useHistory } from "react-router-dom";
|
import { useLocation, useHistory } from "react-router-dom";
|
||||||
import { Header, LeftNav } from "./Header";
|
import { Header, LeftNav, HeaderLogo } from "./Header";
|
||||||
import { Center, Content, Modal } from "./Layout";
|
import { Center, Content, Modal } from "./Layout";
|
||||||
import { ErrorModal } from "./ErrorModal";
|
import { ErrorModal } from "./ErrorModal";
|
||||||
|
|
||||||
|
@ -33,7 +33,9 @@ export function GuestAuthPage({ onLoginAsGuest }) {
|
||||||
return (
|
return (
|
||||||
<div className={styles.guestAuthPage}>
|
<div className={styles.guestAuthPage}>
|
||||||
<Header>
|
<Header>
|
||||||
<LeftNav />
|
<LeftNav>
|
||||||
|
<HeaderLogo />
|
||||||
|
</LeftNav>
|
||||||
</Header>
|
</Header>
|
||||||
<Content>
|
<Content>
|
||||||
<Center>
|
<Center>
|
||||||
|
|
102
src/Header.jsx
102
src/Header.jsx
|
@ -1,67 +1,11 @@
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Link, useHistory } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import styles from "./Header.module.css";
|
import styles from "./Header.module.css";
|
||||||
import { ReactComponent as LogoIcon } from "./Logo.svg";
|
import { ReactComponent as LogoIcon } from "./Logo.svg";
|
||||||
import { ReactComponent as VideoIcon } from "./icons/Video.svg";
|
import { ReactComponent as VideoIcon } from "./icons/Video.svg";
|
||||||
import { ReactComponent as ArrowLeftIcon } from "./icons/ArrowLeft.svg";
|
import { ReactComponent as ArrowLeftIcon } from "./icons/ArrowLeft.svg";
|
||||||
|
import { HeaderDropdownItem, UserMenu } from "./RoomButton";
|
||||||
export function RoomHeader({ roomName, children }) {
|
|
||||||
return (
|
|
||||||
<Header>
|
|
||||||
<LeftNav>
|
|
||||||
<div className={styles.roomAvatar}>
|
|
||||||
<VideoIcon width={16} height={16} />
|
|
||||||
</div>
|
|
||||||
<h3>{roomName}</h3>
|
|
||||||
</LeftNav>
|
|
||||||
<RightNav>{children}</RightNav>
|
|
||||||
</Header>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function RoomSetupHeader({ roomName, children }) {
|
|
||||||
const history = useHistory();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Header>
|
|
||||||
<LeftNav>
|
|
||||||
<button className={styles.backButton} onClick={() => history.goBack()}>
|
|
||||||
<ArrowLeftIcon width={16} height={16} />
|
|
||||||
<div className={styles.roomAvatar}>
|
|
||||||
<VideoIcon width={16} height={16} />
|
|
||||||
</div>
|
|
||||||
<h3>{roomName}</h3>
|
|
||||||
</button>
|
|
||||||
</LeftNav>
|
|
||||||
<RightNav>{children}</RightNav>
|
|
||||||
</Header>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function HomeHeader({ userName, signedIn, onLogout }) {
|
|
||||||
return (
|
|
||||||
<Header>
|
|
||||||
<LeftNav>
|
|
||||||
<Link className={styles.logo} to="/">
|
|
||||||
<LogoIcon width={32} height={32} />
|
|
||||||
</Link>
|
|
||||||
</LeftNav>
|
|
||||||
{signedIn && (
|
|
||||||
<RightNav>
|
|
||||||
<span className={styles.userName}>{userName}</span>
|
|
||||||
<button
|
|
||||||
className={styles.signOutButton}
|
|
||||||
type="button"
|
|
||||||
onClick={onLogout}
|
|
||||||
>
|
|
||||||
Sign Out
|
|
||||||
</button>
|
|
||||||
</RightNav>
|
|
||||||
)}
|
|
||||||
</Header>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function Header({ children, className, ...rest }) {
|
export function Header({ children, className, ...rest }) {
|
||||||
return (
|
return (
|
||||||
|
@ -92,3 +36,45 @@ export function RightNav({ children, className, ...rest }) {
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function HeaderLogo() {
|
||||||
|
return (
|
||||||
|
<Link className={styles.logo} to="/">
|
||||||
|
<LogoIcon width={32} height={32} />
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function RoomHeaderInfo({ roomName }) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className={styles.roomAvatar}>
|
||||||
|
<VideoIcon width={16} height={16} />
|
||||||
|
</div>
|
||||||
|
<h3>{roomName}</h3>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function RoomSetupHeaderInfo({ onBack, roomName }) {
|
||||||
|
return (
|
||||||
|
<button className={styles.backButton} onClick={onBack}>
|
||||||
|
<ArrowLeftIcon width={16} height={16} />
|
||||||
|
<RoomHeaderInfo roomName={roomName} />
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function UserDropdownMenu({ userName, signedIn, onLogout }) {
|
||||||
|
if (!signedIn) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<UserMenu userName={userName}>
|
||||||
|
<HeaderDropdownItem onClick={onLogout} className={styles.signOutButton}>
|
||||||
|
Sign Out
|
||||||
|
</HeaderDropdownItem>
|
||||||
|
</UserMenu>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
21
src/Home.jsx
21
src/Home.jsx
|
@ -20,7 +20,13 @@ import {
|
||||||
useGroupCallRooms,
|
useGroupCallRooms,
|
||||||
usePublicRooms,
|
usePublicRooms,
|
||||||
} from "./ConferenceCallManagerHooks";
|
} from "./ConferenceCallManagerHooks";
|
||||||
import { HomeHeader } from "./Header";
|
import {
|
||||||
|
Header,
|
||||||
|
HeaderLogo,
|
||||||
|
LeftNav,
|
||||||
|
RightNav,
|
||||||
|
UserDropdownMenu,
|
||||||
|
} from "./Header";
|
||||||
import ColorHash from "color-hash";
|
import ColorHash from "color-hash";
|
||||||
import styles from "./Home.module.css";
|
import styles from "./Home.module.css";
|
||||||
import { FieldRow, InputField, Button, ErrorMessage } from "./Input";
|
import { FieldRow, InputField, Button, ErrorMessage } from "./Input";
|
||||||
|
@ -121,7 +127,18 @@ export function Home({ client, onLogout }) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<HomeHeader signedIn userName={client.getUserId()} onLogout={onLogout} />
|
<Header>
|
||||||
|
<LeftNav>
|
||||||
|
<HeaderLogo />
|
||||||
|
</LeftNav>
|
||||||
|
<RightNav>
|
||||||
|
<UserDropdownMenu
|
||||||
|
userName={client.getUserIdLocalpart()}
|
||||||
|
signedIn
|
||||||
|
onLogout={onLogout}
|
||||||
|
/>
|
||||||
|
</RightNav>
|
||||||
|
</Header>
|
||||||
<Content>
|
<Content>
|
||||||
<Center>
|
<Center>
|
||||||
<Modal>
|
<Modal>
|
||||||
|
|
|
@ -109,6 +109,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.checkboxField input {
|
.checkboxField input {
|
||||||
|
outline: 0;
|
||||||
appearance: none;
|
appearance: none;
|
||||||
-webkit-appearance: none;
|
-webkit-appearance: none;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
@ -146,6 +147,10 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.checkboxField:focus-within .checkbox {
|
||||||
|
border: 1.5px solid var(--inputBorderColorFocused) !important;
|
||||||
|
}
|
||||||
|
|
||||||
.button {
|
.button {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
border: 0;
|
border: 0;
|
||||||
|
@ -157,7 +162,6 @@
|
||||||
padding: 7px 15px;
|
padding: 7px 15px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
outline: none;
|
|
||||||
-webkit-box-sizing: border-box;
|
-webkit-box-sizing: border-box;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
||||||
|
|
||||||
import React, { useCallback, useRef, useState } from "react";
|
import React, { useCallback, useRef, useState } from "react";
|
||||||
import { useHistory, useLocation, Link } from "react-router-dom";
|
import { useHistory, useLocation, Link } from "react-router-dom";
|
||||||
import { Header, LeftNav } from "./Header";
|
import { Header, HeaderLogo, LeftNav } from "./Header";
|
||||||
import { FieldRow, InputField, Button, ErrorMessage } from "./Input";
|
import { FieldRow, InputField, Button, ErrorMessage } from "./Input";
|
||||||
import { Center, Content, Info, Modal } from "./Layout";
|
import { Center, Content, Info, Modal } from "./Layout";
|
||||||
|
|
||||||
|
@ -55,7 +55,9 @@ export function LoginPage({ onLogin }) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Header>
|
<Header>
|
||||||
<LeftNav />
|
<LeftNav>
|
||||||
|
<HeaderLogo />
|
||||||
|
</LeftNav>
|
||||||
</Header>
|
</Header>
|
||||||
<Content>
|
<Content>
|
||||||
<Center>
|
<Center>
|
||||||
|
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
||||||
|
|
||||||
import React, { useCallback, useRef, useState } from "react";
|
import React, { useCallback, useRef, useState } from "react";
|
||||||
import { useHistory, useLocation, Link } from "react-router-dom";
|
import { useHistory, useLocation, Link } from "react-router-dom";
|
||||||
import { Header, LeftNav } from "./Header";
|
import { Header, LeftNav, HeaderLogo } from "./Header";
|
||||||
import { FieldRow, InputField, Button, ErrorMessage } from "./Input";
|
import { FieldRow, InputField, Button, ErrorMessage } from "./Input";
|
||||||
import { Center, Content, Info, Modal } from "./Layout";
|
import { Center, Content, Info, Modal } from "./Layout";
|
||||||
|
|
||||||
|
@ -54,7 +54,9 @@ export function RegisterPage({ onRegister }) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Header>
|
<Header>
|
||||||
<LeftNav />
|
<LeftNav>
|
||||||
|
<HeaderLogo />
|
||||||
|
</LeftNav>
|
||||||
</Header>
|
</Header>
|
||||||
<Content>
|
<Content>
|
||||||
<Center>
|
<Center>
|
||||||
|
|
101
src/Room.jsx
101
src/Room.jsx
|
@ -16,7 +16,7 @@ limitations under the License.
|
||||||
|
|
||||||
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
||||||
import styles from "./Room.module.css";
|
import styles from "./Room.module.css";
|
||||||
import { useLocation, useParams } from "react-router-dom";
|
import { useLocation, useParams, useHistory } from "react-router-dom";
|
||||||
import {
|
import {
|
||||||
HangupButton,
|
HangupButton,
|
||||||
MicButton,
|
MicButton,
|
||||||
|
@ -26,7 +26,14 @@ import {
|
||||||
DropdownButton,
|
DropdownButton,
|
||||||
SettingsButton,
|
SettingsButton,
|
||||||
} from "./RoomButton";
|
} from "./RoomButton";
|
||||||
import { Header, LeftNav, RoomHeader, RoomSetupHeader } from "./Header";
|
import {
|
||||||
|
Header,
|
||||||
|
LeftNav,
|
||||||
|
RightNav,
|
||||||
|
RoomHeaderInfo,
|
||||||
|
RoomSetupHeaderInfo,
|
||||||
|
UserDropdownMenu,
|
||||||
|
} from "./Header";
|
||||||
import { Button } from "./Input";
|
import { Button } from "./Input";
|
||||||
import { GroupCallState } from "matrix-js-sdk/src/webrtc/groupCall";
|
import { GroupCallState } from "matrix-js-sdk/src/webrtc/groupCall";
|
||||||
import VideoGrid, {
|
import VideoGrid, {
|
||||||
|
@ -65,7 +72,7 @@ function useLoadGroupCall(client, roomId, viaServers) {
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Room({ client }) {
|
export function Room({ client, onLogout }) {
|
||||||
const { roomId: maybeRoomId } = useParams();
|
const { roomId: maybeRoomId } = useParams();
|
||||||
const { hash, search } = useLocation();
|
const { hash, search } = useLocation();
|
||||||
const [simpleGrid, viaServers] = useMemo(() => {
|
const [simpleGrid, viaServers] = useMemo(() => {
|
||||||
|
@ -94,6 +101,11 @@ export function Room({ client }) {
|
||||||
if (error) {
|
if (error) {
|
||||||
return (
|
return (
|
||||||
<div className={styles.room}>
|
<div className={styles.room}>
|
||||||
|
<Header>
|
||||||
|
<LeftNav>
|
||||||
|
<HeaderLogo />
|
||||||
|
</LeftNav>
|
||||||
|
</Header>
|
||||||
<ErrorModal error={error} />
|
<ErrorModal error={error} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -102,6 +114,7 @@ export function Room({ client }) {
|
||||||
return (
|
return (
|
||||||
<div className={styles.room}>
|
<div className={styles.room}>
|
||||||
<GroupCallView
|
<GroupCallView
|
||||||
|
onLogout={onLogout}
|
||||||
client={client}
|
client={client}
|
||||||
groupCall={groupCall}
|
groupCall={groupCall}
|
||||||
simpleGrid={simpleGrid}
|
simpleGrid={simpleGrid}
|
||||||
|
@ -110,7 +123,7 @@ export function Room({ client }) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function GroupCallView({ client, groupCall, simpleGrid }) {
|
export function GroupCallView({ client, groupCall, simpleGrid, onLogout }) {
|
||||||
const {
|
const {
|
||||||
state,
|
state,
|
||||||
error,
|
error,
|
||||||
|
@ -156,10 +169,20 @@ export function GroupCallView({ client, groupCall, simpleGrid }) {
|
||||||
}, [groupCall]);
|
}, [groupCall]);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
return <ErrorModal error={error} />;
|
return (
|
||||||
|
<>
|
||||||
|
<Header>
|
||||||
|
<LeftNav>
|
||||||
|
<HeaderLogo />
|
||||||
|
</LeftNav>
|
||||||
|
</Header>
|
||||||
|
<ErrorModal error={error} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
} else if (state === GroupCallState.Entered) {
|
} else if (state === GroupCallState.Entered) {
|
||||||
return (
|
return (
|
||||||
<InRoomView
|
<InRoomView
|
||||||
|
onLogout={onLogout}
|
||||||
groupCall={groupCall}
|
groupCall={groupCall}
|
||||||
client={client}
|
client={client}
|
||||||
roomName={groupCall.room.name}
|
roomName={groupCall.room.name}
|
||||||
|
@ -182,6 +205,7 @@ export function GroupCallView({ client, groupCall, simpleGrid }) {
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<RoomSetupView
|
<RoomSetupView
|
||||||
|
onLogout={onLogout}
|
||||||
client={client}
|
client={client}
|
||||||
hasLocalParticipant={hasLocalParticipant}
|
hasLocalParticipant={hasLocalParticipant}
|
||||||
roomName={groupCall.room.name}
|
roomName={groupCall.room.name}
|
||||||
|
@ -219,6 +243,7 @@ export function EnteringRoomView() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function RoomSetupView({
|
function RoomSetupView({
|
||||||
|
onLogout,
|
||||||
client,
|
client,
|
||||||
roomName,
|
roomName,
|
||||||
state,
|
state,
|
||||||
|
@ -231,6 +256,7 @@ function RoomSetupView({
|
||||||
toggleMicrophoneMuted,
|
toggleMicrophoneMuted,
|
||||||
hasLocalParticipant,
|
hasLocalParticipant,
|
||||||
}) {
|
}) {
|
||||||
|
const history = useHistory();
|
||||||
const { stream } = useCallFeed(localCallFeed);
|
const { stream } = useCallFeed(localCallFeed);
|
||||||
const videoRef = useMediaStream(stream, true);
|
const videoRef = useMediaStream(stream, true);
|
||||||
|
|
||||||
|
@ -249,7 +275,21 @@ function RoomSetupView({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<RoomSetupHeader roomName={roomName} />
|
<Header>
|
||||||
|
<LeftNav>
|
||||||
|
<RoomSetupHeaderInfo
|
||||||
|
onBack={() => history.goBack()}
|
||||||
|
roomName={roomName}
|
||||||
|
/>
|
||||||
|
</LeftNav>
|
||||||
|
<RightNav>
|
||||||
|
<UserDropdownMenu
|
||||||
|
userName={client.getUserIdLocalpart()}
|
||||||
|
signedIn
|
||||||
|
onLogout={onLogout}
|
||||||
|
/>
|
||||||
|
</RightNav>
|
||||||
|
</Header>
|
||||||
<div className={styles.joinRoom}>
|
<div className={styles.joinRoom}>
|
||||||
{hasLocalParticipant && (
|
{hasLocalParticipant && (
|
||||||
<p>Warning, you are signed into this call on another device.</p>
|
<p>Warning, you are signed into this call on another device.</p>
|
||||||
|
@ -380,6 +420,7 @@ function useMediaHandler(client) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function InRoomView({
|
function InRoomView({
|
||||||
|
onLogout,
|
||||||
client,
|
client,
|
||||||
groupCall,
|
groupCall,
|
||||||
roomName,
|
roomName,
|
||||||
|
@ -397,7 +438,7 @@ function InRoomView({
|
||||||
}) {
|
}) {
|
||||||
const [showInspector, setShowInspector] = useState(false);
|
const [showInspector, setShowInspector] = useState(false);
|
||||||
|
|
||||||
const [layout, toggleLayout] = useVideoGridLayout();
|
const [layout, setLayout] = useVideoGridLayout();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
audioInput,
|
audioInput,
|
||||||
|
@ -408,12 +449,6 @@ function InRoomView({
|
||||||
setVideoInput,
|
setVideoInput,
|
||||||
} = useMediaHandler(client);
|
} = useMediaHandler(client);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (screenshareFeeds.length > 0 && layout === "gallery") {
|
|
||||||
toggleLayout();
|
|
||||||
}
|
|
||||||
}, [screenshareFeeds]);
|
|
||||||
|
|
||||||
const items = useMemo(() => {
|
const items = useMemo(() => {
|
||||||
const participants = [];
|
const participants = [];
|
||||||
|
|
||||||
|
@ -440,7 +475,7 @@ function InRoomView({
|
||||||
|
|
||||||
const onFocusTile = useCallback(
|
const onFocusTile = useCallback(
|
||||||
(tiles, focusedTile) => {
|
(tiles, focusedTile) => {
|
||||||
if (layout === "gallery") {
|
if (layout === "freedom") {
|
||||||
return tiles.map((tile) => {
|
return tiles.map((tile) => {
|
||||||
if (tile === focusedTile) {
|
if (tile === focusedTile) {
|
||||||
return { ...tile, presenter: !tile.presenter };
|
return { ...tile, presenter: !tile.presenter };
|
||||||
|
@ -449,7 +484,7 @@ function InRoomView({
|
||||||
return tile;
|
return tile;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
toggleLayout();
|
setLayout("spotlight");
|
||||||
|
|
||||||
return tiles.map((tile) => {
|
return tiles.map((tile) => {
|
||||||
if (tile === focusedTile) {
|
if (tile === focusedTile) {
|
||||||
|
@ -460,23 +495,33 @@ function InRoomView({
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[layout, toggleLayout]
|
[layout, setLayout]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<RoomHeader roomName={roomName}>
|
<Header>
|
||||||
<SettingsButton
|
<LeftNav>
|
||||||
title={showInspector ? "Hide Inspector" : "Show Inspector"}
|
<RoomHeaderInfo roomName={roomName} />
|
||||||
on={showInspector}
|
</LeftNav>
|
||||||
onClick={() => setShowInspector((prev) => !prev)}
|
<RightNav>
|
||||||
/>
|
<SettingsButton
|
||||||
<LayoutToggleButton
|
title={showInspector ? "Hide Inspector" : "Show Inspector"}
|
||||||
title={layout === "spotlight" ? "Spotlight" : "Gallery"}
|
on={showInspector}
|
||||||
layout={layout}
|
onClick={() => setShowInspector((prev) => !prev)}
|
||||||
onClick={toggleLayout}
|
/>
|
||||||
/>
|
<LayoutToggleButton
|
||||||
</RoomHeader>
|
title={layout === "spotlight" ? "Spotlight" : "Freedom"}
|
||||||
|
layout={layout}
|
||||||
|
setLayout={setLayout}
|
||||||
|
/>
|
||||||
|
<UserDropdownMenu
|
||||||
|
userName={client.getUserIdLocalpart()}
|
||||||
|
signedIn
|
||||||
|
onLogout={onLogout}
|
||||||
|
/>
|
||||||
|
</RightNav>
|
||||||
|
</Header>
|
||||||
{items.length === 0 ? (
|
{items.length === 0 ? (
|
||||||
<div className={styles.centerMessage}>
|
<div className={styles.centerMessage}>
|
||||||
<p>Waiting for other participants...</p>
|
<p>Waiting for other participants...</p>
|
||||||
|
|
|
@ -11,6 +11,8 @@ import { ReactComponent as FreedomIcon } from "./icons/Freedom.svg";
|
||||||
import { ReactComponent as SpotlightIcon } from "./icons/Spotlight.svg";
|
import { ReactComponent as SpotlightIcon } from "./icons/Spotlight.svg";
|
||||||
import { ReactComponent as ScreenshareIcon } from "./icons/Screenshare.svg";
|
import { ReactComponent as ScreenshareIcon } from "./icons/Screenshare.svg";
|
||||||
import { ReactComponent as ChevronIcon } from "./icons/Chevron.svg";
|
import { ReactComponent as ChevronIcon } from "./icons/Chevron.svg";
|
||||||
|
import { ReactComponent as UserIcon } from "./icons/User.svg";
|
||||||
|
import { ReactComponent as CheckIcon } from "./icons/Check.svg";
|
||||||
|
|
||||||
export function RoomButton({ on, className, children, ...rest }) {
|
export function RoomButton({ on, className, children, ...rest }) {
|
||||||
return (
|
return (
|
||||||
|
@ -134,6 +136,72 @@ export function HeaderButton({ on, className, children, ...rest }) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function HeaderDropdownButton({ children, content }) {
|
||||||
|
const buttonRef = useRef();
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
function onClick() {
|
||||||
|
if (open) {
|
||||||
|
setOpen(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener("click", onClick);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener("click", onClick);
|
||||||
|
};
|
||||||
|
}, [open]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.dropdownButtonContainer}>
|
||||||
|
<button
|
||||||
|
ref={buttonRef}
|
||||||
|
className={classNames(styles.headerButton, { [styles.on]: open })}
|
||||||
|
onClick={() => setOpen(true)}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</button>
|
||||||
|
{open && (
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
styles.dropdownContainer,
|
||||||
|
styles.headerDropdownContainer
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<ul>{content}</ul>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function HeaderDropdownItem({ active, children, className, ...rest }) {
|
||||||
|
return (
|
||||||
|
<li
|
||||||
|
className={classNames(className, {
|
||||||
|
[styles.dropdownActiveItem]: active,
|
||||||
|
})}
|
||||||
|
{...rest}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function UserMenu({ userName, children }) {
|
||||||
|
return (
|
||||||
|
<HeaderDropdownButton content={children}>
|
||||||
|
<ButtonTooltip>Profile</ButtonTooltip>
|
||||||
|
<div className={styles.userButton}>
|
||||||
|
<UserIcon />
|
||||||
|
<span>{userName}</span>
|
||||||
|
</div>
|
||||||
|
</HeaderDropdownButton>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export function SettingsButton(props) {
|
export function SettingsButton(props) {
|
||||||
return (
|
return (
|
||||||
<HeaderButton {...props}>
|
<HeaderButton {...props}>
|
||||||
|
@ -143,16 +211,30 @@ export function SettingsButton(props) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function LayoutToggleButton({ layout, ...rest }) {
|
export function LayoutToggleButton({ layout, setLayout, ...rest }) {
|
||||||
return (
|
return (
|
||||||
<HeaderButton {...rest}>
|
<HeaderDropdownButton
|
||||||
<ButtonTooltip className={styles.bottomRight}>Layout Type</ButtonTooltip>
|
{...rest}
|
||||||
{layout === "spotlight" ? (
|
content={
|
||||||
<SpotlightIcon width={24} height={24} />
|
<>
|
||||||
) : (
|
<HeaderDropdownItem onClick={() => setLayout("freedom")}>
|
||||||
<FreedomIcon width={24} height={24} />
|
<FreedomIcon />
|
||||||
)}
|
<span>Freedom</span>
|
||||||
</HeaderButton>
|
{layout === "freedom" && <CheckIcon className={styles.checkIcon} />}
|
||||||
|
</HeaderDropdownItem>
|
||||||
|
<HeaderDropdownItem onClick={() => setLayout("spotlight")}>
|
||||||
|
<SpotlightIcon />
|
||||||
|
<span>Spotlight</span>
|
||||||
|
{layout === "spotlight" && (
|
||||||
|
<CheckIcon className={styles.checkIcon} />
|
||||||
|
)}
|
||||||
|
</HeaderDropdownItem>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<ButtonTooltip>Layout Type</ButtonTooltip>
|
||||||
|
{layout === "spotlight" ? <SpotlightIcon /> : <FreedomIcon />}
|
||||||
|
</HeaderDropdownButton>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,10 @@ limitations under the License.
|
||||||
fill: #8d97a5;
|
fill: #8d97a5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.headerButton:hover svg * {
|
||||||
|
fill: #8d97a5;
|
||||||
|
}
|
||||||
|
|
||||||
.headerButton.on svg * {
|
.headerButton.on svg * {
|
||||||
fill: #0dbd8b;
|
fill: #0dbd8b;
|
||||||
}
|
}
|
||||||
|
@ -99,6 +103,21 @@ limitations under the License.
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.headerDropdownContainer {
|
||||||
|
transform: translate(-100%, 36px);
|
||||||
|
left: 100%;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkIcon {
|
||||||
|
position: absolute;
|
||||||
|
right: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkIcon * {
|
||||||
|
stroke: var(--textColor1);
|
||||||
|
}
|
||||||
|
|
||||||
.dropdownContainer ul {
|
.dropdownContainer ul {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
@ -106,9 +125,21 @@ limitations under the License.
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropdownContainer li {
|
.dropdownContainer li {
|
||||||
|
position: relative;
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
width: 200px;
|
width: 200px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
font-size: 15px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdownContainer li > * {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdownContainer li > :last-child {
|
||||||
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropdownContainer li:hover {
|
.dropdownContainer li:hover {
|
||||||
|
@ -147,3 +178,31 @@ limitations under the License.
|
||||||
display: flex;
|
display: flex;
|
||||||
top: calc(100% + 6px);
|
top: calc(100% + 6px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.userButton {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
color: var(--textColor1);
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.userButton > * {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.userButton svg * {
|
||||||
|
fill: var(--textColor1) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.headerButton:hover .userButton > * {
|
||||||
|
color: var(--textColor1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.headerButton:hover .userButton svg * {
|
||||||
|
fill: var(--textColor1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.userButton > :last-child {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
|
4
src/icons/AddUser.svg
Normal file
4
src/icons/AddUser.svg
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M18.8914 9.0784C18.5132 9.0784 18.2066 8.777 18.2066 8.4052V5.71251H15.4678C15.0896 5.71251 14.783 5.41111 14.783 5.03931C14.783 4.66751 15.0896 4.36611 15.4678 4.36611H18.2066V1.6732C18.2066 1.3014 18.5132 1 18.8914 1C19.2696 1 19.5761 1.3014 19.5761 1.6732V4.36611H22.3153C22.6934 4.36611 23 4.66751 23 5.03931C23 5.41111 22.6934 5.71251 22.3153 5.71251H19.5761V8.4052C19.5761 8.777 19.2696 9.0784 18.8914 9.0784Z" fill="#8E99A4"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M19.5002 11.5094C19.8949 11.5094 20.281 11.4736 20.6555 11.4051C20.7505 11.9558 20.8 12.5221 20.8 13.1C20.8 18.5676 16.3676 23 10.9 23C5.43238 23 1 18.5676 1 13.1C1 7.63238 5.43238 3.2 10.9 3.2C11.7973 3.2 12.6666 3.31937 13.4931 3.54308C13.3177 4.11118 13.2234 4.71396 13.2234 5.33841C13.2234 8.74655 16.0336 11.5094 19.5002 11.5094ZM11.1308 21.4653C13.2927 21.4653 15.2551 20.6258 16.6993 19.2603C15.7939 17.0769 13.6417 15.5412 11.1308 15.5412C8.61988 15.5412 6.46768 17.0769 5.56225 19.2603C7.00643 20.6258 8.96888 21.4653 11.1308 21.4653ZM11.2799 7.81768C9.78854 7.9515 8.62035 9.18434 8.62035 10.6854C8.62035 12.2759 9.93179 13.5652 11.5495 13.5652C12.6276 13.5652 13.5696 12.9927 14.0781 12.1401C12.6655 11.1035 11.6462 9.57751 11.2799 7.81768Z" fill="#8E99A4"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
|
@ -1,4 +1,7 @@
|
||||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path d="M18.8914 9.0784C18.5132 9.0784 18.2066 8.777 18.2066 8.4052V5.71251H15.4678C15.0896 5.71251 14.783 5.41111 14.783 5.03931C14.783 4.66751 15.0896 4.36611 15.4678 4.36611H18.2066V1.6732C18.2066 1.3014 18.5132 1 18.8914 1C19.2696 1 19.5761 1.3014 19.5761 1.6732V4.36611H22.3153C22.6934 4.36611 23 4.66751 23 5.03931C23 5.41111 22.6934 5.71251 22.3153 5.71251H19.5761V8.4052C19.5761 8.777 19.2696 9.0784 18.8914 9.0784Z" fill="#8E99A4"/>
|
<mask id="path-1-inside-1_898_2641" fill="white">
|
||||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M19.5002 11.5094C19.8949 11.5094 20.281 11.4736 20.6555 11.4051C20.7505 11.9558 20.8 12.5221 20.8 13.1C20.8 18.5676 16.3676 23 10.9 23C5.43238 23 1 18.5676 1 13.1C1 7.63238 5.43238 3.2 10.9 3.2C11.7973 3.2 12.6666 3.31937 13.4931 3.54308C13.3177 4.11118 13.2234 4.71396 13.2234 5.33841C13.2234 8.74655 16.0336 11.5094 19.5002 11.5094ZM11.1308 21.4653C13.2927 21.4653 15.2551 20.6258 16.6993 19.2603C15.7939 17.0769 13.6417 15.5412 11.1308 15.5412C8.61988 15.5412 6.46768 17.0769 5.56225 19.2603C7.00643 20.6258 8.96888 21.4653 11.1308 21.4653ZM11.2799 7.81768C9.78854 7.9515 8.62035 9.18434 8.62035 10.6854C8.62035 12.2759 9.93179 13.5652 11.5495 13.5652C12.6276 13.5652 13.5696 12.9927 14.0781 12.1401C12.6655 11.1035 11.6462 9.57751 11.2799 7.81768Z" fill="#8E99A4"/>
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M17.1502 20.1214C15.3946 21.3074 13.2782 22 11 22C8.52367 22 6.23845 21.1817 4.4 19.8008C1.72821 17.794 0 14.5988 0 11C0 4.92487 4.92487 0 11 0C17.0751 0 22 4.92487 22 11C22 14.797 20.0762 18.1446 17.1502 20.1214ZM11 11.55C12.8225 11.55 14.3 9.94942 14.3 7.975C14.3 6.00058 12.8225 4.4 11 4.4C9.17746 4.4 7.7 6.00058 7.7 7.975C7.7 9.94942 9.17746 11.55 11 11.55ZM11 19.8C13.3782 19.8 15.536 18.8566 17.1197 17.3237C16.1403 14.9056 13.7693 13.2 11 13.2C8.23066 13.2 5.85969 14.9056 4.88028 17.3237C6.46399 18.8566 8.62183 19.8 11 19.8Z"/>
|
||||||
|
</mask>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M17.1502 20.1214C15.3946 21.3074 13.2782 22 11 22C8.52367 22 6.23845 21.1817 4.4 19.8008C1.72821 17.794 0 14.5988 0 11C0 4.92487 4.92487 0 11 0C17.0751 0 22 4.92487 22 11C22 14.797 20.0762 18.1446 17.1502 20.1214ZM11 11.55C12.8225 11.55 14.3 9.94942 14.3 7.975C14.3 6.00058 12.8225 4.4 11 4.4C9.17746 4.4 7.7 6.00058 7.7 7.975C7.7 9.94942 9.17746 11.55 11 11.55ZM11 19.8C13.3782 19.8 15.536 18.8566 17.1197 17.3237C16.1403 14.9056 13.7693 13.2 11 13.2C8.23066 13.2 5.85969 14.9056 4.88028 17.3237C6.46399 18.8566 8.62183 19.8 11 19.8Z" fill="white"/>
|
||||||
|
<path d="M17.1502 20.1214L17.9339 21.2814L17.1502 20.1214ZM4.4 19.8008L3.55919 20.9202H3.55919L4.4 19.8008ZM17.1197 17.3237L18.0934 18.3296L18.7717 17.6731L18.4173 16.7981L17.1197 17.3237ZM4.88028 17.3237L3.58268 16.7981L3.22829 17.6731L3.90659 18.3296L4.88028 17.3237ZM11 23.4C13.5662 23.4 15.9541 22.619 17.9339 21.2814L16.3665 18.9613C14.835 19.9959 12.9902 20.6 11 20.6V23.4ZM3.55919 20.9202C5.63176 22.477 8.21011 23.4 11 23.4V20.6C8.83723 20.6 6.84514 19.8865 5.24081 18.6814L3.55919 20.9202ZM-1.4 11C-1.4 15.0577 0.55052 18.6603 3.55919 20.9202L5.24081 18.6814C2.90591 16.9276 1.4 14.1399 1.4 11H-1.4ZM11 -1.4C4.15167 -1.4 -1.4 4.15167 -1.4 11H1.4C1.4 5.69807 5.69807 1.4 11 1.4V-1.4ZM23.4 11C23.4 4.15167 17.8483 -1.4 11 -1.4V1.4C16.3019 1.4 20.6 5.69807 20.6 11H23.4ZM17.9339 21.2814C21.2288 19.0554 23.4 15.2815 23.4 11H20.6C20.6 14.3124 18.9236 17.2337 16.3665 18.9613L17.9339 21.2814ZM12.9 7.975C12.9 9.28384 11.9459 10.15 11 10.15V12.95C13.6991 12.95 15.7 10.615 15.7 7.975H12.9ZM11 5.8C11.9459 5.8 12.9 6.66616 12.9 7.975H15.7C15.7 5.335 13.6991 3 11 3V5.8ZM9.1 7.975C9.1 6.66616 10.0541 5.8 11 5.8V3C8.30086 3 6.3 5.335 6.3 7.975H9.1ZM11 10.15C10.0541 10.15 9.1 9.28384 9.1 7.975H6.3C6.3 10.615 8.30086 12.95 11 12.95V10.15ZM16.146 16.3178C14.8129 17.6081 13.0004 18.4 11 18.4V21.2C13.756 21.2 16.2591 20.1051 18.0934 18.3296L16.146 16.3178ZM11 14.6C13.1797 14.6 15.0494 15.9415 15.8221 17.8493L18.4173 16.7981C17.2312 13.8697 14.359 11.8 11 11.8V14.6ZM6.17788 17.8493C6.95058 15.9415 8.8203 14.6 11 14.6V11.8C7.64102 11.8 4.7688 13.8697 3.58268 16.7981L6.17788 17.8493ZM11 18.4C8.99963 18.4 7.18709 17.6081 5.85397 16.3178L3.90659 18.3296C5.74088 20.1051 8.24402 21.2 11 21.2V18.4Z" fill="white" mask="url(#path-1-inside-1_898_2641)"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 3 KiB |
Loading…
Reference in a new issue