diff --git a/src/App.jsx b/src/App.jsx index 2bf7a03..52150b8 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -67,7 +67,7 @@ export default function App() { {authenticated ? ( - + ) : ( )} diff --git a/src/ConferenceCallManagerHooks.js b/src/ConferenceCallManagerHooks.js index fac1188..7d15018 100644 --- a/src/ConferenceCallManagerHooks.js +++ b/src/ConferenceCallManagerHooks.js @@ -249,8 +249,8 @@ export function useClient(homeserverUrl) { const logout = useCallback(() => { localStorage.removeItem("matrix-auth-store"); - setState({ client: undefined, loading: false, authenticated: false }); - }, []); + window.location = "/"; + }, [history]); return { loading, diff --git a/src/GuestAuthPage.jsx b/src/GuestAuthPage.jsx index 08bd363..4011ba2 100644 --- a/src/GuestAuthPage.jsx +++ b/src/GuestAuthPage.jsx @@ -17,7 +17,7 @@ limitations under the License. import React, { useState, useEffect } from "react"; import styles from "./GuestAuthPage.module.css"; 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 { ErrorModal } from "./ErrorModal"; @@ -33,7 +33,9 @@ export function GuestAuthPage({ onLoginAsGuest }) { return (
- + + +
diff --git a/src/Header.jsx b/src/Header.jsx index 0140527..6486035 100644 --- a/src/Header.jsx +++ b/src/Header.jsx @@ -1,67 +1,11 @@ import classNames from "classnames"; import React from "react"; -import { Link, useHistory } from "react-router-dom"; +import { Link } from "react-router-dom"; import styles from "./Header.module.css"; import { ReactComponent as LogoIcon } from "./Logo.svg"; import { ReactComponent as VideoIcon } from "./icons/Video.svg"; import { ReactComponent as ArrowLeftIcon } from "./icons/ArrowLeft.svg"; - -export function RoomHeader({ roomName, children }) { - return ( -
- -
- -
-

{roomName}

-
- {children} -
- ); -} - -export function RoomSetupHeader({ roomName, children }) { - const history = useHistory(); - - return ( -
- - - - {children} -
- ); -} - -export function HomeHeader({ userName, signedIn, onLogout }) { - return ( -
- - - - - - {signedIn && ( - - {userName} - - - )} -
- ); -} +import { HeaderDropdownItem, UserMenu } from "./RoomButton"; export function Header({ children, className, ...rest }) { return ( @@ -92,3 +36,45 @@ export function RightNav({ children, className, ...rest }) {
); } + +export function HeaderLogo() { + return ( + + + + ); +} + +export function RoomHeaderInfo({ roomName }) { + return ( + <> +
+ +
+

{roomName}

+ + ); +} + +export function RoomSetupHeaderInfo({ onBack, roomName }) { + return ( + + ); +} + +export function UserDropdownMenu({ userName, signedIn, onLogout }) { + if (!signedIn) { + return null; + } + + return ( + + + Sign Out + + + ); +} diff --git a/src/Home.jsx b/src/Home.jsx index bdf896d..81a4653 100644 --- a/src/Home.jsx +++ b/src/Home.jsx @@ -20,7 +20,13 @@ import { useGroupCallRooms, usePublicRooms, } from "./ConferenceCallManagerHooks"; -import { HomeHeader } from "./Header"; +import { + Header, + HeaderLogo, + LeftNav, + RightNav, + UserDropdownMenu, +} from "./Header"; import ColorHash from "color-hash"; import styles from "./Home.module.css"; import { FieldRow, InputField, Button, ErrorMessage } from "./Input"; @@ -121,7 +127,18 @@ export function Home({ client, onLogout }) { return ( <> - +
+ + + + + + +
diff --git a/src/Input.module.css b/src/Input.module.css index 4a8e875..cdbd654 100644 --- a/src/Input.module.css +++ b/src/Input.module.css @@ -109,6 +109,7 @@ } .checkboxField input { + outline: 0; appearance: none; -webkit-appearance: none; margin: 0; @@ -146,6 +147,10 @@ display: flex; } +.checkboxField:focus-within .checkbox { + border: 1.5px solid var(--inputBorderColorFocused) !important; +} + .button { vertical-align: middle; border: 0; @@ -157,7 +162,6 @@ padding: 7px 15px; cursor: pointer; display: inline-block; - outline: none; -webkit-box-sizing: border-box; box-sizing: border-box; text-align: center; diff --git a/src/LoginPage.jsx b/src/LoginPage.jsx index fe62fc1..0b07823 100644 --- a/src/LoginPage.jsx +++ b/src/LoginPage.jsx @@ -16,7 +16,7 @@ limitations under the License. import React, { useCallback, useRef, useState } from "react"; 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 { Center, Content, Info, Modal } from "./Layout"; @@ -55,7 +55,9 @@ export function LoginPage({ onLogin }) { return ( <>
- + + +
diff --git a/src/RegisterPage.jsx b/src/RegisterPage.jsx index dbb6eb6..1930ea9 100644 --- a/src/RegisterPage.jsx +++ b/src/RegisterPage.jsx @@ -16,7 +16,7 @@ limitations under the License. import React, { useCallback, useRef, useState } from "react"; 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 { Center, Content, Info, Modal } from "./Layout"; @@ -54,7 +54,9 @@ export function RegisterPage({ onRegister }) { return ( <>
- + + +
diff --git a/src/Room.jsx b/src/Room.jsx index d42236b..860a4c5 100644 --- a/src/Room.jsx +++ b/src/Room.jsx @@ -16,7 +16,7 @@ limitations under the License. import React, { useCallback, useEffect, useMemo, useState } from "react"; import styles from "./Room.module.css"; -import { useLocation, useParams } from "react-router-dom"; +import { useLocation, useParams, useHistory } from "react-router-dom"; import { HangupButton, MicButton, @@ -26,7 +26,14 @@ import { DropdownButton, SettingsButton, } from "./RoomButton"; -import { Header, LeftNav, RoomHeader, RoomSetupHeader } from "./Header"; +import { + Header, + LeftNav, + RightNav, + RoomHeaderInfo, + RoomSetupHeaderInfo, + UserDropdownMenu, +} from "./Header"; import { Button } from "./Input"; import { GroupCallState } from "matrix-js-sdk/src/webrtc/groupCall"; import VideoGrid, { @@ -65,7 +72,7 @@ function useLoadGroupCall(client, roomId, viaServers) { return state; } -export function Room({ client }) { +export function Room({ client, onLogout }) { const { roomId: maybeRoomId } = useParams(); const { hash, search } = useLocation(); const [simpleGrid, viaServers] = useMemo(() => { @@ -94,6 +101,11 @@ export function Room({ client }) { if (error) { return (
+
+ + + +
); @@ -102,6 +114,7 @@ export function Room({ client }) { return (
; + return ( + <> +
+ + + +
+ + + ); } else if (state === GroupCallState.Entered) { return ( - +
+ + history.goBack()} + roomName={roomName} + /> + + + + +
{hasLocalParticipant && (

Warning, you are signed into this call on another device.

@@ -380,6 +420,7 @@ function useMediaHandler(client) { } function InRoomView({ + onLogout, client, groupCall, roomName, @@ -397,7 +438,7 @@ function InRoomView({ }) { const [showInspector, setShowInspector] = useState(false); - const [layout, toggleLayout] = useVideoGridLayout(); + const [layout, setLayout] = useVideoGridLayout(); const { audioInput, @@ -408,12 +449,6 @@ function InRoomView({ setVideoInput, } = useMediaHandler(client); - useEffect(() => { - if (screenshareFeeds.length > 0 && layout === "gallery") { - toggleLayout(); - } - }, [screenshareFeeds]); - const items = useMemo(() => { const participants = []; @@ -440,7 +475,7 @@ function InRoomView({ const onFocusTile = useCallback( (tiles, focusedTile) => { - if (layout === "gallery") { + if (layout === "freedom") { return tiles.map((tile) => { if (tile === focusedTile) { return { ...tile, presenter: !tile.presenter }; @@ -449,7 +484,7 @@ function InRoomView({ return tile; }); } else { - toggleLayout(); + setLayout("spotlight"); return tiles.map((tile) => { if (tile === focusedTile) { @@ -460,23 +495,33 @@ function InRoomView({ }); } }, - [layout, toggleLayout] + [layout, setLayout] ); return ( <> - - setShowInspector((prev) => !prev)} - /> - - +
+ + + + + setShowInspector((prev) => !prev)} + /> + + + +
{items.length === 0 ? (

Waiting for other participants...

diff --git a/src/RoomButton.jsx b/src/RoomButton.jsx index a89b2da..e5b89ad 100644 --- a/src/RoomButton.jsx +++ b/src/RoomButton.jsx @@ -11,6 +11,8 @@ import { ReactComponent as FreedomIcon } from "./icons/Freedom.svg"; import { ReactComponent as SpotlightIcon } from "./icons/Spotlight.svg"; import { ReactComponent as ScreenshareIcon } from "./icons/Screenshare.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 }) { 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 ( +
+ + {open && ( +
+
    {content}
+
+ )} +
+ ); +} + +export function HeaderDropdownItem({ active, children, className, ...rest }) { + return ( +
  • + {children} +
  • + ); +} + +export function UserMenu({ userName, children }) { + return ( + + Profile +
    + + {userName} +
    +
    + ); +} + export function SettingsButton(props) { return ( @@ -143,16 +211,30 @@ export function SettingsButton(props) { ); } -export function LayoutToggleButton({ layout, ...rest }) { +export function LayoutToggleButton({ layout, setLayout, ...rest }) { return ( - - Layout Type - {layout === "spotlight" ? ( - - ) : ( - - )} - + + setLayout("freedom")}> + + Freedom + {layout === "freedom" && } + + setLayout("spotlight")}> + + Spotlight + {layout === "spotlight" && ( + + )} + + + } + > + Layout Type + {layout === "spotlight" ? : } + ); } diff --git a/src/RoomButton.module.css b/src/RoomButton.module.css index 49ac089..428ad9b 100644 --- a/src/RoomButton.module.css +++ b/src/RoomButton.module.css @@ -53,6 +53,10 @@ limitations under the License. fill: #8d97a5; } +.headerButton:hover svg * { + fill: #8d97a5; +} + .headerButton.on svg * { fill: #0dbd8b; } @@ -99,6 +103,21 @@ limitations under the License. overflow: hidden; } +.headerDropdownContainer { + transform: translate(-100%, 36px); + left: 100%; + z-index: 1; +} + +.checkIcon { + position: absolute; + right: 16px; +} + +.checkIcon * { + stroke: var(--textColor1); +} + .dropdownContainer ul { list-style: none; margin: 0; @@ -106,9 +125,21 @@ limitations under the License. } .dropdownContainer li { + position: relative; padding: 12px; width: 200px; 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 { @@ -147,3 +178,31 @@ limitations under the License. display: flex; 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; +} diff --git a/src/icons/AddUser.svg b/src/icons/AddUser.svg new file mode 100644 index 0000000..c1cc54c --- /dev/null +++ b/src/icons/AddUser.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/icons/User.svg b/src/icons/User.svg index c1cc54c..e397c62 100644 --- a/src/icons/User.svg +++ b/src/icons/User.svg @@ -1,4 +1,7 @@ - - - + + + + + +