diff --git a/src/Menu.module.css b/src/Menu.module.css index 8291e5880..64e1286e5 100644 --- a/src/Menu.module.css +++ b/src/Menu.module.css @@ -39,3 +39,12 @@ border-bottom-left-radius: 8px; border-bottom-right-radius: 8px; } + +.checkIcon { + position: absolute; + right: 16px; +} + +.checkIcon * { + stroke: var(--textColor1); +} diff --git a/src/button/Button.jsx b/src/button/Button.jsx index 85754b370..d93987eb5 100644 --- a/src/button/Button.jsx +++ b/src/button/Button.jsx @@ -25,6 +25,7 @@ import { ReactComponent as HangupIcon } from "../icons/Hangup.svg"; import { ReactComponent as ScreenshareIcon } from "../icons/Screenshare.svg"; import { ReactComponent as SettingsIcon } from "../icons/Settings.svg"; import { ReactComponent as AddUserIcon } from "../icons/AddUser.svg"; +import { ReactComponent as ArrowDownIcon } from "../icons/ArrowDown.svg"; import { useButton } from "@react-aria/button"; import { mergeProps, useObjectRef } from "@react-aria/utils"; import { TooltipTrigger } from "../Tooltip"; @@ -36,9 +37,11 @@ export const variantToClassName = { icon: [styles.iconButton], secondary: [styles.secondary], copy: [styles.copyButton], + secondaryCopy: [styles.secondaryCopy], iconCopy: [styles.iconCopyButton], secondaryCopy: [styles.copyButton], secondaryHangup: [styles.secondaryHangup], + dropdown: [styles.dropdownButton], }; export const sizeToClassName = { @@ -86,13 +89,13 @@ export const Button = forwardRef( { [styles.on]: on, [styles.off]: off, - [styles.secondaryCopy]: variant === "secondaryCopy", } )} {...mergeProps(rest, filteredButtonProps)} ref={buttonRef} > {children} + {variant === "dropdown" && } ); } diff --git a/src/button/Button.module.css b/src/button/Button.module.css index 5c3ec3004..a76eaec4a 100644 --- a/src/button/Button.module.css +++ b/src/button/Button.module.css @@ -21,7 +21,8 @@ limitations under the License. .iconCopyButton, .secondary, .secondaryHangup, -.copyButton { +.copyButton, +.dropdownButton { position: relative; display: flex; justify-content: center; @@ -184,6 +185,25 @@ limitations under the License. stroke: #0dbd8b; } +.dropdownButton { + color: var(--textColor1); + padding: 2px 8px; + border-radius: 8px; +} + +.dropdownButton:hover, +.dropdownButton.on { + background-color: var(--bgColor4); +} + +.dropdownButton svg { + margin-left: 8px; +} + +.dropdownButton svg * { + fill: var(--textColor1); +} + .lg { height: 40px; } diff --git a/src/home/CallTypeDropdown.module.css b/src/home/CallTypeDropdown.module.css new file mode 100644 index 000000000..82074be23 --- /dev/null +++ b/src/home/CallTypeDropdown.module.css @@ -0,0 +1,3 @@ +.label { + margin-bottom: 0; +} diff --git a/src/home/CallTypeDropdown.tsx b/src/home/CallTypeDropdown.tsx new file mode 100644 index 000000000..b84dd773c --- /dev/null +++ b/src/home/CallTypeDropdown.tsx @@ -0,0 +1,69 @@ +/* +Copyright 2022 Matrix.org Foundation C.I.C. + +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, { FC } from "react"; +import { Item } from "@react-stately/collections"; + +import { Headline } from "../typography/Typography"; +import { Button } from "../button"; +import { PopoverMenuTrigger } from "../popover/PopoverMenu"; +import { ReactComponent as VideoIcon } from "../icons/Video.svg"; +import { ReactComponent as MicIcon } from "../icons/Mic.svg"; +import { ReactComponent as CheckIcon } from "../icons/Check.svg"; +import styles from "./CallTypeDropdown.module.css"; +import commonStyles from "./common.module.css"; +import menuStyles from "../Menu.module.css"; +import { Menu } from "../Menu"; + +export enum CallType { + Video = "video", + Radio = "radio", +} + +interface Props { + callType: CallType; + setCallType: (value: CallType) => void; +} + +export const CallTypeDropdown: FC = ({ callType, setCallType }) => { + return ( + + + {(props) => ( + + + + Video call + {callType === CallType.Video && ( + + )} + + + + Radio call + {callType === CallType.Radio && ( + + )} + + + )} + + ); +}; diff --git a/src/home/RegisteredView.jsx b/src/home/RegisteredView.jsx index 02d87a170..0fc1b3e2b 100644 --- a/src/home/RegisteredView.jsx +++ b/src/home/RegisteredView.jsx @@ -27,21 +27,21 @@ import { UserMenuContainer } from "../UserMenuContainer"; import { useModalTriggerState } from "../Modal"; import { JoinExistingCallModal } from "./JoinExistingCallModal"; import { useHistory } from "react-router-dom"; -import { Headline, Title } from "../typography/Typography"; +import { Title } from "../typography/Typography"; import { Form } from "../form/Form"; -import { useShouldShowPtt } from "../useShouldShowPtt"; +import { CallType, CallTypeDropdown } from "./CallTypeDropdown"; export function RegisteredView({ client }) { + const [callType, setCallType] = useState(CallType.Video); const [loading, setLoading] = useState(false); const [error, setError] = useState(); const history = useHistory(); - const shouldShowPtt = useShouldShowPtt(); const onSubmit = useCallback( (e) => { e.preventDefault(); const data = new FormData(e.target); const roomName = data.get("callName"); - const ptt = data.get("ptt") !== null; + const ptt = callType === CallType.Radio; async function submit() { setError(undefined); @@ -68,7 +68,7 @@ export function RegisteredView({ client }) { } }); }, - [client] + [client, callType] ); const recentRooms = useGroupCallRooms(client); @@ -79,6 +79,9 @@ export function RegisteredView({ client }) { history.push(`/${existingRoomId}`); }, [history, existingRoomId]); + const callNameLabel = + callType === CallType.Video ? "Video call name" : "Radio call name"; + return ( <>
@@ -92,16 +95,14 @@ export function RegisteredView({ client }) {
- - Enter a call name - +
- {shouldShowPtt && ( - - - - )} {error && ( {error.message} diff --git a/src/home/UnauthenticatedView.jsx b/src/home/UnauthenticatedView.jsx index e8adbcecd..51e8eedd1 100644 --- a/src/home/UnauthenticatedView.jsx +++ b/src/home/UnauthenticatedView.jsx @@ -29,14 +29,14 @@ import { JoinExistingCallModal } from "./JoinExistingCallModal"; import { useRecaptcha } from "../auth/useRecaptcha"; import { Body, Caption, Link, Headline } from "../typography/Typography"; import { Form } from "../form/Form"; +import { CallType, CallTypeDropdown } from "./CallTypeDropdown"; import styles from "./UnauthenticatedView.module.css"; import commonStyles from "./common.module.css"; import { generateRandomName } from "../auth/generateRandomName"; -import { useShouldShowPtt } from "../useShouldShowPtt"; export function UnauthenticatedView() { const { setClient } = useClient(); - const shouldShowPtt = useShouldShowPtt(); + const [callType, setCallType] = useState(CallType.Video); const [loading, setLoading] = useState(false); const [error, setError] = useState(); const [{ privacyPolicyUrl, recaptchaKey }, register] = @@ -53,7 +53,7 @@ export function UnauthenticatedView() { const data = new FormData(e.target); const roomName = data.get("callName"); const displayName = data.get("displayName"); - const ptt = data.get("ptt") !== null; + const ptt = callType === CallType.Radio; async function submit() { setError(undefined); @@ -100,9 +100,12 @@ export function UnauthenticatedView() { reset(); }); }, - [register, reset, execute, history] + [register, reset, execute, history, callType] ); + const callNameLabel = + callType === CallType.Video ? "Video call name" : "Radio call name"; + return ( <>
@@ -116,16 +119,14 @@ export function UnauthenticatedView() {
- - Enter a call name - + - {shouldShowPtt && ( - - - - )} By clicking "Go", you agree to our{" "} Terms and conditions diff --git a/src/index.css b/src/index.css index 1084a880e..25562e314 100644 --- a/src/index.css +++ b/src/index.css @@ -123,6 +123,7 @@ limitations under the License. body { background-color: var(--bgColor1); color: var(--textColor1); + color-scheme: dark; margin: 0; font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", diff --git a/src/room/GridLayoutMenu.jsx b/src/room/GridLayoutMenu.jsx index 2a95373c8..02f324bf4 100644 --- a/src/room/GridLayoutMenu.jsx +++ b/src/room/GridLayoutMenu.jsx @@ -20,7 +20,7 @@ import { PopoverMenuTrigger } from "../popover/PopoverMenu"; import { ReactComponent as SpotlightIcon } from "../icons/Spotlight.svg"; import { ReactComponent as FreedomIcon } from "../icons/Freedom.svg"; import { ReactComponent as CheckIcon } from "../icons/Check.svg"; -import styles from "./GridLayoutMenu.module.css"; +import menuStyles from "../Menu.module.css"; import { Menu } from "../Menu"; import { Item } from "@react-stately/collections"; import { Tooltip, TooltipTrigger } from "../Tooltip"; @@ -39,13 +39,15 @@ export function GridLayoutMenu({ layout, setLayout }) { Freedom - {layout === "freedom" && } + {layout === "freedom" && ( + + )} Spotlight {layout === "spotlight" && ( - + )} diff --git a/src/room/GridLayoutMenu.module.css b/src/room/GridLayoutMenu.module.css index 8056f311d..e69de29bb 100644 --- a/src/room/GridLayoutMenu.module.css +++ b/src/room/GridLayoutMenu.module.css @@ -1,8 +0,0 @@ -.checkIcon { - position: absolute; - right: 16px; -} - -.checkIcon * { - stroke: var(--textColor1); -} diff --git a/src/useShouldShowPtt.js b/src/useShouldShowPtt.js deleted file mode 100644 index 606a68913..000000000 --- a/src/useShouldShowPtt.js +++ /dev/null @@ -1,6 +0,0 @@ -import { useLocation } from "react-router-dom"; - -export function useShouldShowPtt() { - const { hash } = useLocation(); - return hash.startsWith("#ptt"); -}