diff --git a/src/App.jsx b/src/App.jsx index cff79008..183faa71 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -24,9 +24,10 @@ import { } from "react-router-dom"; import { useConferenceCallManager } from "./ConferenceCallManagerHooks"; import { Home } from "./Home"; -import { LoginOrRegister } from "./LoginOrRegister"; import { Room } from "./Room"; import { GridDemo } from "./GridDemo"; +import { RegisterPage } from "./RegisterPage"; +import { LoginPage } from "./LoginPage"; export default function App() { const { protocol, host } = window.location; @@ -38,23 +39,24 @@ export default function App() { return ( <> - {error &&

{error.message}

} {loading ? (

Loading...

) : ( - - {authenticated ? ( - - ) : ( - - )} + + + + + + + + - + @@ -76,7 +78,7 @@ function AuthenticatedRoute({ authenticated, children, ...rest }) { ) : ( diff --git a/src/Header.jsx b/src/Header.jsx index 6573b38c..568f3097 100644 --- a/src/Header.jsx +++ b/src/Header.jsx @@ -38,3 +38,18 @@ export function RightNav({ children, className, ...rest }) { ); } + +export function UserNav({ signedIn, userName, onLogout }) { + if (!signedIn) { + return null; + } + + return ( + + {userName} + + + ); +} diff --git a/src/Header.module.css b/src/Header.module.css index 55c3eef3..54d99812 100644 --- a/src/Header.module.css +++ b/src/Header.module.css @@ -5,6 +5,7 @@ align-items: center; height: 98px; user-select: none; + flex-shrink: 0; } .leftNav { @@ -21,5 +22,24 @@ .rightNav { position: absolute; right: 20px; - max-width: 30%; -} \ No newline at end of file + max-width: 33%; + white-space: nowrap; + display: flex; +} + +.userName { + font-weight: 600; + margin-right: 8px; + text-overflow: ellipsis; + overflow: hidden; + flex-shrink: 1; +} + +.signOutButton { + background: transparent; + border: none; + color: rgb(255, 75, 85); + cursor: pointer; + font-weight: 600; + flex-shrink: 0; +} diff --git a/src/Home.jsx b/src/Home.jsx index 2251b86e..727c72f7 100644 --- a/src/Home.jsx +++ b/src/Home.jsx @@ -17,10 +17,11 @@ limitations under the License. import React, { useCallback, useRef, useState } from "react"; import { useHistory, Link } from "react-router-dom"; import { useRooms } from "./ConferenceCallManagerHooks"; -import { Header, LeftNav, RightNav } from "./Header"; +import { Header, LeftNav, UserNav } from "./Header"; import ColorHash from "color-hash"; import styles from "./Home.module.css"; -import { FieldRow, InputField, Button } from "./Input"; +import { FieldRow, InputField, Button, ErrorMessage } from "./Input"; +import { Center, Content, Sidebar, Modal } from "./Layout"; const colorHash = new ColorHash({ lightness: 0.3 }); @@ -62,21 +63,14 @@ export function Home({ manager }) { <>
- - - {manager.client && manager.client.getUserId()} - - - +
-
-
+ +
Rooms:
{rooms.map((room) => ( @@ -95,29 +89,35 @@ export function Home({ manager }) { ))}
-
-
-
-

Create New Room

- - - - {createRoomError &&

{createRoomError.message}

} - - - -
-
-
+ +
+ +
+

Create New Room

+ + + + {createRoomError && ( + + {createRoomError.message} + + )} + + + +
+
+
+ ); } diff --git a/src/Home.module.css b/src/Home.module.css index 1c30d98a..81b696dd 100644 --- a/src/Home.module.css +++ b/src/Home.module.css @@ -1,23 +1,3 @@ -.content { - display: grid; - grid-template-columns: minmax(200px, 320px) 3fr; - gap: 20px; - margin: 0 20px; - flex: 1; -} - -.roomsSidebar { - padding: 12px; - background-color: rgba(33,38,44,.9); - border-radius: 8px; -} - -.roomsSidebar h5 { - color: rgb(142, 153, 164); - font-size: 13px; - margin: 0 0 8px 0; -} - .roomList { } @@ -65,35 +45,3 @@ font-size: 14px; line-height: 18px; } - -.center { - flex: 1; - display: flex; - justify-content: center; - align-items: center; -} - -.createRoomContainer { - color: #232f32; - border-radius: 8px; - padding: 25px 60px; - width: 400px; - background-color: white; -} - -.createRoomContainer h2 { - margin: 0 0 20px 0; -} - -.userName { - font-weight: 600; - margin-right: 8px; -} - -.signOutButton { - background: transparent; - border: none; - color: rgb(255, 75, 85); - cursor: pointer; - font-weight: 600; -} diff --git a/src/Input.jsx b/src/Input.jsx index 13604925..c79cd4bc 100644 --- a/src/Input.jsx +++ b/src/Input.jsx @@ -25,7 +25,7 @@ export const InputField = forwardRef( return ( - + ); } @@ -42,3 +42,7 @@ export const Button = forwardRef(({ className, children, ...rest }, ref) => { ); }); + +export function ErrorMessage({ children }) { + return

{children}

; +} diff --git a/src/Input.module.css b/src/Input.module.css index 2dde3afd..4fd1079f 100644 --- a/src/Input.module.css +++ b/src/Input.module.css @@ -69,9 +69,16 @@ max-width: calc(100% - 20px); } -.field input:focus + label { +.field:focus-within { + border-color: #238cf5; +} + +.field input:focus { + outline: 0; +} + +.field input:focus + label, .field input:not(:placeholder-shown) + label { background-color: #fff; - color: #238cf5; transition: font-size .25s ease-out 0s,color .25s ease-out 0s,top .25s ease-out 0s,background-color .25s ease-out 0s; font-size: 10px; top: -13px; @@ -80,6 +87,10 @@ pointer-events: auto; } +.field input:focus + label { + color: #238cf5; +} + .button { vertical-align: middle; border: 0; @@ -104,4 +115,11 @@ .button:active { +} + +.errorMessage { + margin: 0; + font-size: 13px; + color: rgb(255, 75, 85); + font-weight: 600; } \ No newline at end of file diff --git a/src/Layout.jsx b/src/Layout.jsx new file mode 100644 index 00000000..f97d3921 --- /dev/null +++ b/src/Layout.jsx @@ -0,0 +1,43 @@ +import React from "react"; +import classNames from "classnames"; +import styles from "./Layout.module.css"; + +export function Content({ children, className, ...rest }) { + return ( +
+ {children} +
+ ); +} + +export function Sidebar({ children, className, ...rest }) { + return ( + + ); +} + +export function Center({ children, className, ...rest }) { + return ( +
+ {children} +
+ ); +} + +export function Modal({ children, className, ...rest }) { + return ( +
+ {children} +
+ ); +} + +export function Info({ children, className, ...rest }) { + return ( +

+ {children} +

+ ); +} diff --git a/src/Layout.module.css b/src/Layout.module.css new file mode 100644 index 00000000..1852dea8 --- /dev/null +++ b/src/Layout.module.css @@ -0,0 +1,69 @@ +.content { + display: flex; + flex-direction: column; + margin: 0 20px; + flex: 1; +} + +.sidebar { + display: flex; + flex-direction: column; + height: auto; + flex: 1; + min-width: 200px; + width: auto; + max-width: none; + padding: 12px; + background-color: rgba(33,38,44,.9); + border-radius: 8px; + margin-bottom: 20px; +} + +.sidebar h5 { + color: rgb(142, 153, 164); + font-size: 13px; + margin: 0 0 8px 0; +} + +.center { + display: flex; + flex: 1; + justify-content: center; + align-items: center; +} + +.modal { + color: #232f32; + border-radius: 8px; + padding: 25px 60px; + max-width: 400px; + background-color: white; + flex: 1; + margin-bottom: 20px; +} + +.modal h2 { + margin: 0 0 20px 0; +} + +.info { + font-size: 13px; + text-align: center; +} + +@media (min-width: 600px) { + .sidebar { + height: 100%; + overflow-y: auto; + max-width: 320px; + margin-bottom: 0; + } + + .content { + flex-direction: row; + } + + .modal { + margin-bottom: 0; + } +} \ No newline at end of file diff --git a/src/LoginOrRegister.jsx b/src/LoginOrRegister.jsx deleted file mode 100644 index 29251759..00000000 --- a/src/LoginOrRegister.jsx +++ /dev/null @@ -1,93 +0,0 @@ -/* -Copyright 2021 New Vector Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import React, { useCallback, useRef } from "react"; -import { useHistory, useLocation } from "react-router-dom"; - -export function LoginOrRegister({ onRegister, onLogin }) { - const registerUsernameRef = useRef(); - const registerPasswordRef = useRef(); - const loginUsernameRef = useRef(); - const loginPasswordRef = useRef(); - const history = useHistory(); - const location = useLocation(); - - const onSubmitRegisterForm = useCallback( - (e) => { - e.preventDefault(); - onRegister( - registerUsernameRef.current.value, - registerPasswordRef.current.value, - () => { - if (location.state && location.state.from) { - history.replace(location.state.from); - } - } - ); - }, - [onRegister, location, history] - ); - - const onSubmitLoginForm = useCallback( - (e) => { - e.preventDefault(); - onLogin( - loginUsernameRef.current.value, - loginPasswordRef.current.value, - () => { - if (location.state && location.state.from) { - history.replace(location.state.from); - } - } - ); - }, - [onLogin, location, history] - ); - - return ( -
-

Matrix Video Chat

-

Register

-
- - - -
-

Login

-
- - - -
-
- ); -} diff --git a/src/LoginPage.jsx b/src/LoginPage.jsx new file mode 100644 index 00000000..8e735033 --- /dev/null +++ b/src/LoginPage.jsx @@ -0,0 +1,98 @@ +/* +Copyright 2021 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React, { useCallback, useRef } from "react"; +import { useHistory, useLocation, Link } from "react-router-dom"; +import { Header, LeftNav } from "./Header"; +import { FieldRow, InputField, Button, ErrorMessage } from "./Input"; +import { Center, Content, Info, Modal } from "./Layout"; + +export function LoginPage({ onLogin, error }) { + const loginUsernameRef = useRef(); + const loginPasswordRef = useRef(); + const history = useHistory(); + const location = useLocation(); + + const onSubmitLoginForm = useCallback( + (e) => { + e.preventDefault(); + onLogin( + loginUsernameRef.current.value, + loginPasswordRef.current.value, + () => { + if (location.state && location.state.from) { + history.replace(location.state.from); + } else { + history.replace("/"); + } + } + ); + }, + [onLogin, location, history] + ); + + return ( + <> +
+ +
+ +
+ +

Login

+
+ + + + + + + {error && ( + + {error.message} + + )} + + + +
+ + New?{" "} + + Create account + + +
+
+
+ + ); +} diff --git a/src/RegisterPage.jsx b/src/RegisterPage.jsx new file mode 100644 index 00000000..eb3d9257 --- /dev/null +++ b/src/RegisterPage.jsx @@ -0,0 +1,98 @@ +/* +Copyright 2021 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React, { useCallback, useRef } from "react"; +import { useHistory, useLocation, Link } from "react-router-dom"; +import { Header, LeftNav } from "./Header"; +import { FieldRow, InputField, Button } from "./Input"; +import { Center, Content, Info, Modal } from "./Layout"; + +export function RegisterPage({ onRegister, error }) { + const registerUsernameRef = useRef(); + const registerPasswordRef = useRef(); + const history = useHistory(); + const location = useLocation(); + + const onSubmitRegisterForm = useCallback( + (e) => { + e.preventDefault(); + onRegister( + registerUsernameRef.current.value, + registerPasswordRef.current.value, + () => { + if (location.state && location.state.from) { + history.replace(location.state.from); + } else { + history.replace("/"); + } + } + ); + }, + [onRegister, location, history] + ); + + return ( + <> +
+ +
+ +
+ +

Register

+
+ + + + + + + {error && ( + + {error.message} + + )} + + + +
+ + Already have an account?{" "} + + Sign in here + + +
+
+
+ + ); +} diff --git a/src/Room.jsx b/src/Room.jsx index dd464459..eca7c0f7 100644 --- a/src/Room.jsx +++ b/src/Room.jsx @@ -14,9 +14,9 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, { useEffect, useMemo, useRef, useState } from "react"; +import React, { useEffect, useMemo, useState } from "react"; import styles from "./Room.module.css"; -import { useParams, useLocation, Link } from "react-router-dom"; +import { useParams, useLocation } from "react-router-dom"; import { useVideoRoom } from "./ConferenceCallManagerHooks"; import { DevTools } from "./DevTools"; import { VideoGrid } from "./VideoGrid";