Transition to modals and popovers

This commit is contained in:
Robert Long 2021-12-03 16:42:29 -08:00
parent 742fdab56d
commit f57b520622
19 changed files with 507 additions and 75 deletions

View file

@ -9,9 +9,12 @@
"@react-aria/button": "^3.3.4",
"@react-aria/dialog": "^3.1.4",
"@react-aria/focus": "^3.5.0",
"@react-aria/menu": "^3.3.0",
"@react-aria/overlays": "^3.7.3",
"@react-aria/utils": "^3.10.0",
"@react-stately/collections": "^3.3.4",
"@react-stately/overlays": "^3.1.3",
"@react-stately/tree": "^3.2.0",
"@sentry/react": "^6.13.3",
"@sentry/tracing": "^6.13.3",
"classnames": "^2.3.1",

View file

@ -22,8 +22,6 @@ import {
Redirect,
useLocation,
} from "react-router-dom";
import styles from "./App.module.css";
import { OverlayProvider } from "@react-aria/overlays";
import * as Sentry from "@sentry/react";
import { useClient } from "./ConferenceCallManagerHooks";
import { Home } from "./Home";
@ -50,36 +48,34 @@ export default function App() {
} = useClient(homeserverUrl);
return (
<OverlayProvider className={styles.overlayProvider}>
<Router>
<>
{loading ? (
<Center>
<p>Loading...</p>
</Center>
) : (
<Switch>
<AuthenticatedRoute authenticated={authenticated} exact path="/">
<Home client={client} onLogout={logout} />
</AuthenticatedRoute>
<SentryRoute exact path="/login">
<LoginPage onLogin={login} />
</SentryRoute>
<SentryRoute exact path="/register">
<RegisterPage onRegister={register} />
</SentryRoute>
<SentryRoute path="/room/:roomId?">
{authenticated ? (
<Room client={client} onLogout={logout} />
) : (
<GuestAuthPage onLoginAsGuest={registerGuest} />
)}
</SentryRoute>
</Switch>
)}
</>
</Router>
</OverlayProvider>
<Router>
<>
{loading ? (
<Center>
<p>Loading...</p>
</Center>
) : (
<Switch>
<AuthenticatedRoute authenticated={authenticated} exact path="/">
<Home client={client} onLogout={logout} />
</AuthenticatedRoute>
<SentryRoute exact path="/login">
<LoginPage onLogin={login} />
</SentryRoute>
<SentryRoute exact path="/register">
<RegisterPage onRegister={register} />
</SentryRoute>
<SentryRoute path="/room/:roomId?">
{authenticated ? (
<Room client={client} onLogout={logout} />
) : (
<GuestAuthPage onLoginAsGuest={registerGuest} />
)}
</SentryRoute>
</Switch>
)}
</>
</Router>
);
}

View file

@ -1,5 +0,0 @@
.overlayProvider {
display: flex;
flex-direction: column;
height: 100%;
}

36
src/GridLayoutMenu.jsx Normal file
View file

@ -0,0 +1,36 @@
import React, { useCallback } from "react";
import { ButtonTooltip, HeaderButton } from "./RoomButton";
import { Popover, PopoverMenu, PopoverMenuItem } from "./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";
export function GridLayoutMenu({ layout, setLayout }) {
const onAction = useCallback((value) => setLayout(value));
return (
<PopoverMenu onAction={onAction} placement="bottom right">
<HeaderButton>
<ButtonTooltip>Layout Type</ButtonTooltip>
{layout === "spotlight" ? <SpotlightIcon /> : <FreedomIcon />}
</HeaderButton>
{(props) => (
<Popover {...props} label="Grid layout menu">
<PopoverMenuItem key="freedom" textValue="Freedom">
<FreedomIcon />
<span>Freedom</span>
{layout === "freedom" && <CheckIcon className={styles.checkIcon} />}
</PopoverMenuItem>
<PopoverMenuItem key="spotlight" textValue="Spotlight">
<SpotlightIcon />
<span>Spotlight</span>
{layout === "spotlight" && (
<CheckIcon className={styles.checkIcon} />
)}
</PopoverMenuItem>
</Popover>
)}
</PopoverMenu>
);
}

View file

@ -0,0 +1,8 @@
.checkIcon {
position: absolute;
right: 16px;
}
.checkIcon * {
stroke: var(--textColor1);
}

31
src/OverflowMenu.jsx Normal file
View file

@ -0,0 +1,31 @@
import React, { useCallback } from "react";
import { ButtonTooltip, RoomButton } from "./RoomButton";
import { Popover, PopoverMenu, PopoverMenuItem } from "./PopoverMenu";
import { ReactComponent as SettingsIcon } from "./icons/Settings.svg";
import { ReactComponent as AddUserIcon } from "./icons/AddUser.svg";
import { ReactComponent as OverflowIcon } from "./icons/Overflow.svg";
export function OverflowMenu({ roomUrl }) {
const onAction = useCallback((e) => console.log(e));
return (
<PopoverMenu onAction={onAction}>
<RoomButton>
<ButtonTooltip>More</ButtonTooltip>
<OverflowIcon />
</RoomButton>
{(props) => (
<Popover {...props} label="More menu">
<PopoverMenuItem key="invite" textValue="Invite people">
<AddUserIcon />
<span>Invite people</span>
</PopoverMenuItem>
<PopoverMenuItem key="settings" textValue="Settings">
<SettingsIcon />
<span>Settings</span>
</PopoverMenuItem>
</Popover>
)}
</PopoverMenu>
);
}

145
src/PopoverMenu.jsx Normal file
View file

@ -0,0 +1,145 @@
import React, { useRef, useState, forwardRef } from "react";
import styles from "./PopoverMenu.module.css";
import { useMenuTriggerState } from "@react-stately/menu";
import { useButton } from "@react-aria/button";
import { useMenu, useMenuItem, useMenuTrigger } from "@react-aria/menu";
import { useTreeState } from "@react-stately/tree";
import { Item } from "@react-stately/collections";
import { mergeProps } from "@react-aria/utils";
import { FocusScope } from "@react-aria/focus";
import { useFocus } from "@react-aria/interactions";
import {
useOverlay,
DismissButton,
useOverlayPosition,
OverlayContainer,
} from "@react-aria/overlays";
import classNames from "classnames";
export function PopoverMenu({ children, placement, ...rest }) {
const popoverMenuState = useMenuTriggerState(rest);
const buttonRef = useRef();
const { menuTriggerProps, menuProps } = useMenuTrigger(
{},
popoverMenuState,
buttonRef
);
const popoverRef = useRef();
const { overlayProps: positionProps } = useOverlayPosition({
targetRef: buttonRef,
overlayRef: popoverRef,
placement: placement || "top",
offset: 5,
isOpen: popoverMenuState.isOpen,
});
if (
!Array.isArray(children) ||
children.length > 2 ||
typeof children[1] !== "function"
) {
throw new Error(
"PopoverMenu must have two props. The first being a button and the second being a render prop."
);
}
const [popoverTrigger, popover] = children;
return (
<div style={{ position: "relative", display: "inline-block" }}>
<popoverTrigger.type
{...popoverTrigger.props}
{...menuTriggerProps}
ref={buttonRef}
/>
{popoverMenuState.isOpen &&
popover({
isOpen: popoverMenuState.isOpen,
onClose: popoverMenuState.close,
autoFocus: popoverMenuState.focusStrategy,
domProps: menuProps,
ref: popoverRef,
positionProps,
...rest,
})}
</div>
);
}
export const Popover = forwardRef((props, ref) => {
const state = useTreeState({ ...props, selectionMode: "none" });
const menuRef = useRef();
const { menuProps } = useMenu(props, state, menuRef);
const { overlayProps } = useOverlay(
{
onClose: props.onClose,
shouldCloseOnBlur: true,
isOpen: true,
isDismissable: true,
},
ref
);
return (
<OverlayContainer>
<FocusScope restoreFocus>
<div
className={styles.popover}
{...mergeProps(overlayProps, props.positionProps)}
ref={ref}
>
<DismissButton onDismiss={props.onClose} />
<ul
{...mergeProps(menuProps, props.domProps)}
ref={menuRef}
className={styles.popoverMenu}
>
{[...state.collection].map((item) => (
<PopoverMenuItemContainer
key={item.key}
item={item}
state={state}
onAction={props.onAction}
onClose={props.onClose}
/>
))}
</ul>
<DismissButton onDismiss={props.onClose} />
</div>
</FocusScope>
</OverlayContainer>
);
});
function PopoverMenuItemContainer({ item, state, onAction, onClose }) {
const ref = useRef();
const { menuItemProps } = useMenuItem(
{
key: item.key,
isDisabled: item.isDisabled,
onAction,
onClose,
},
state,
ref
);
const [isFocused, setFocused] = useState(false);
const { focusProps } = useFocus({ onFocusChange: setFocused });
return (
<li
{...mergeProps(menuItemProps, focusProps)}
ref={ref}
className={classNames(styles.popoverMenuItem, {
[styles.focused]: isFocused,
})}
>
{item.rendered}
</li>
);
}
export const PopoverMenuItem = Item;

View file

@ -0,0 +1,48 @@
.popover {
display: flex;
flex-direction: column;
width: 194px;
background: var(--bgColor2);
box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25);
border-radius: 8px;
}
.popoverMenu {
width: 100%;
padding: 0;
margin: 0;
list-style: none;
}
.popoverMenuItem {
cursor: pointer;
height: 48px;
display: flex;
align-items: center;
padding: 0 12px;
color: var(--textColor1);
}
.popoverMenuItem > * {
margin-right: 10px;
}
.popoverMenuItem > :last-child {
margin-right: 0;
}
.popoverMenuItem.focused,
.popoverMenuItem:hover {
background-color: var(--bgColor3);
outline: none;
}
.popoverMenuItem.focused:first-child,
.popoverMenuItem:hover:first-child {
border-radius: 8px 8px 0 0;
}
.popoverMenuItem.focused:last-child,
.popoverMenuItem:hover:last-child {
border-radius: 0 0 8px 8px;
}

View file

@ -48,6 +48,9 @@ import { ErrorModal } from "./ErrorModal";
import { GroupCallInspector } from "./GroupCallInspector";
import * as Sentry from "@sentry/react";
import { InviteModalButton } from "./InviteModal";
import { OverflowMenu } from "./OverflowMenu";
import { GridLayoutMenu } from "./GridLayoutMenu";
import { UserMenu } from "./UserMenu";
const canScreenshare = "getDisplayMedia" in navigator.mediaDevices;
// There is currently a bug in Safari our our code with cloning and sending MediaStreams
@ -505,15 +508,10 @@ function InRoomView({
<RoomHeaderInfo roomName={roomName} />
</LeftNav>
<RightNav>
<InviteModalButton roomUrl={window.location.href} />
<LayoutToggleButton
title={layout === "spotlight" ? "Spotlight" : "Freedom"}
layout={layout}
setLayout={setLayout}
/>
<UserDropdownMenu
userName={client.getUserIdLocalpart()}
<GridLayoutMenu layout={layout} setLayout={setLayout} />
<UserMenu
signedIn
userName={client.getUserIdLocalpart()}
onLogout={onLogout}
/>
</RightNav>
@ -533,36 +531,19 @@ function InRoomView({
/>
)}
<div className={styles.footer}>
<DropdownButton
value={audioInput}
onChange={({ value }) => setAudioInput(value)}
options={audioInputs.map(({ label, deviceId }) => ({
label,
value: deviceId,
}))}
>
<MicButton muted={microphoneMuted} onClick={toggleMicrophoneMuted} />
</DropdownButton>
<DropdownButton
value={videoInput}
onChange={({ value }) => setVideoInput(value)}
options={videoInputs.map(({ label, deviceId }) => ({
label,
value: deviceId,
}))}
>
<VideoButton
enabled={localVideoMuted}
onClick={toggleLocalVideoMuted}
/>
</DropdownButton>
<MicButton muted={microphoneMuted} onPress={toggleMicrophoneMuted} />
<VideoButton
enabled={localVideoMuted}
onPress={toggleLocalVideoMuted}
/>
{canScreenshare && !isSafari && (
<ScreenshareButton
enabled={isScreensharing}
onClick={toggleScreensharing}
onPress={toggleScreensharing}
/>
)}
<HangupButton onClick={onLeave} />
<OverflowMenu roomUrl={window.location.href} />
<HangupButton onPress={onLeave} />
</div>
<GroupCallInspector
client={client}

View file

@ -13,15 +13,17 @@ 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";
import { useButton } from "@react-aria/button";
export const RoomButton = forwardRef(
({ on, className, children, ...rest }, ref) => {
const { buttonProps } = useButton(rest, ref);
return (
<button
className={classNames(styles.roomButton, className, {
[styles.on]: on,
})}
{...rest}
{...buttonProps}
ref={ref}
>
{children}
@ -130,12 +132,13 @@ export function HangupButton({ className, ...rest }) {
export const HeaderButton = forwardRef(
({ on, className, children, ...rest }, ref) => {
const { buttonProps } = useButton(rest, ref);
return (
<button
className={classNames(styles.headerButton, className, {
[styles.on]: on,
})}
{...rest}
{...buttonProps}
ref={ref}
>
{children}

69
src/UserMenu.jsx Normal file
View file

@ -0,0 +1,69 @@
import React, { useCallback, useMemo } from "react";
import { ButtonTooltip, HeaderButton } from "./RoomButton";
import { Popover, PopoverMenu, PopoverMenuItem } from "./PopoverMenu";
import { ReactComponent as UserIcon } from "./icons/User.svg";
import { ReactComponent as LoginIcon } from "./icons/Login.svg";
import { ReactComponent as LogoutIcon } from "./icons/Logout.svg";
import styles from "./UserMenu.module.css";
export function UserMenu({ userName, signedIn, onLogin, onLogout }) {
const onAction = useCallback((value) => {
switch (value) {
case "user":
break;
case "logout":
onLogout();
break;
case "login":
onLogin();
break;
}
});
const items = useMemo(() => {
if (signedIn) {
return [
{
key: "user",
icon: UserIcon,
label: userName,
},
{
key: "logout",
label: "Sign Out",
icon: LogoutIcon,
},
];
} else {
return [
{
key: "login",
label: "Sign In",
icon: LoginIcon,
},
];
}
}, [signedIn, userName]);
return (
<PopoverMenu onAction={onAction} placement="bottom right">
<HeaderButton>
<ButtonTooltip>Profile</ButtonTooltip>
<div className={styles.userButton}>
<UserIcon />
<span>{userName}</span>
</div>
</HeaderButton>
{(props) => (
<Popover {...props} label="User menu">
{items.map(({ key, icon: Icon, label }) => (
<PopoverMenuItem key={key} textValue={label}>
<Icon />
<span>{label}</span>
</PopoverMenuItem>
))}
</Popover>
)}
</PopoverMenu>
);
}

19
src/UserMenu.module.css Normal file
View file

@ -0,0 +1,19 @@
.userButton {
display: flex;
align-items: center;
color: var(--textColor1);
font-weight: 600;
font-size: 15px;
}
.userButton svg * {
fill: var(--textColor1);
}
.userButton > * {
margin-right: 5px;
}
.userButton > :last-child {
margin-right: 0;
}

View file

@ -1,4 +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"/>
<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="#ffffff"/>
<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="#ffffff"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

3
src/icons/Login.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 24 KiB

3
src/icons/Logout.svg Normal file
View file

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M18.2139 2.44646L12 3.99992H5.4375C4.64359 3.99992 4 4.64352 4 5.43742V18.5624C4 19.3563 4.64359 19.9999 5.4375 19.9999H12L18.2139 21.5534C19.1211 21.7802 20 21.094 20 20.1588V3.84104C20 2.90584 19.1211 2.21964 18.2139 2.44646ZM12 17.9999V5.99992H6V17.9999H12Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 429 B

5
src/icons/Overflow.svg Normal file
View file

@ -0,0 +1,5 @@
<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.33398 15C8.33398 16.3807 7.2147 17.5 5.83398 17.5C4.45327 17.5 3.33398 16.3807 3.33398 15C3.33398 13.6193 4.45327 12.5 5.83398 12.5C7.2147 12.5 8.33398 13.6193 8.33398 15Z" fill="white"/>
<path d="M17.5002 15C17.5002 16.3807 16.381 17.5 15.0002 17.5C13.6195 17.5 12.5002 16.3807 12.5002 15C12.5002 13.6193 13.6195 12.5 15.0002 12.5C16.381 12.5 17.5002 13.6193 17.5002 15Z" fill="white"/>
<path d="M24.1665 17.5C25.5472 17.5 26.6665 16.3807 26.6665 15C26.6665 13.6193 25.5472 12.5 24.1665 12.5C22.7858 12.5 21.6665 13.6193 21.6665 15C21.6665 16.3807 22.7858 17.5 24.1665 17.5Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 707 B

View file

@ -1,3 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M20.0988 9.01625C20.3188 9.59375 20.8825 9.97875 21.5013 9.97875C22.3263 9.97875 23 10.6525 23 11.4775V12.5225C23 13.3475 22.3263 14.0213 21.5013 14.0213C20.8825 14.0213 20.3188 14.4062 20.0988 14.9838C20.0806 15.0292 20.0624 15.0753 20.0441 15.1218C19.9792 15.2863 19.9125 15.4555 19.8375 15.6163C19.5763 16.18 19.7 16.84 20.14 17.28C20.7313 17.8575 20.7313 18.8062 20.14 19.3975L19.3975 20.14C18.82 20.7313 17.8713 20.7313 17.28 20.14C16.8538 19.7 16.18 19.5763 15.6163 19.8375C15.41 19.9338 15.2037 20.0163 14.9838 20.0988C14.4062 20.3188 14.0213 20.8825 14.0213 21.5013C14.0213 22.3263 13.3475 23 12.5225 23H11.4775C10.6525 23 9.97875 22.3263 9.97875 21.5013C9.97875 20.8825 9.59375 20.3188 9.01625 20.0988C8.97079 20.0806 8.92466 20.0624 8.87815 20.044C8.71368 19.9792 8.54454 19.9125 8.38375 19.8375C7.82 19.5763 7.16 19.7 6.72 20.14C6.1425 20.7313 5.19375 20.7313 4.6025 20.14L3.86 19.3975C3.26875 18.82 3.26875 17.8713 3.86 17.28C4.3 16.8538 4.42375 16.18 4.1625 15.6163C4.06625 15.41 3.98375 15.2037 3.90125 14.9838C3.68125 14.4062 3.1175 14.0213 2.49875 14.0213C1.67375 14.0213 1 13.3475 1 12.5225V11.4775C1 10.6525 1.67375 9.97875 2.49875 9.97875C3.1175 9.97875 3.68125 9.59375 3.90125 9.01625C3.94464 8.87742 3.99897 8.74406 4.0539 8.60926C4.086 8.53046 4.11831 8.45117 4.14875 8.37C4.41 7.80625 4.28625 7.14625 3.84625 6.70625C3.255 6.12875 3.255 5.18 3.84625 4.58875L4.6025 3.86C5.18 3.26875 6.12875 3.26875 6.72 3.86C7.14625 4.3 7.82 4.42375 8.38375 4.1625C8.59 4.06625 8.79625 3.97 9.01625 3.90125C9.59375 3.68125 9.97875 3.1175 9.97875 2.49875C9.97875 1.67375 10.6525 1 11.4775 1H12.5225C13.3475 1 14.0213 1.67375 14.0213 2.49875C14.0213 3.13125 14.4062 3.68125 14.9838 3.90125C15.0292 3.91943 15.0753 3.93762 15.1218 3.95595C15.2863 4.02079 15.4555 4.08746 15.6163 4.1625C16.18 4.42375 16.84 4.3 17.28 3.86C17.8575 3.26875 18.8062 3.26875 19.3975 3.86L20.14 4.6025C20.7313 5.18 20.7313 6.12875 20.14 6.72C19.7 7.14625 19.5763 7.82 19.8375 8.38375C19.9338 8.59 20.0163 8.79625 20.0988 9.01625ZM12 17.5C8.96125 17.5 6.5 15.0387 6.5 12C6.5 8.96125 8.96125 6.5 12 6.5C15.0387 6.5 17.5 8.96125 17.5 12C17.5 15.0387 15.0387 17.5 12 17.5Z" fill="#8E99A4"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M20.0988 9.01625C20.3188 9.59375 20.8825 9.97875 21.5013 9.97875C22.3263 9.97875 23 10.6525 23 11.4775V12.5225C23 13.3475 22.3263 14.0213 21.5013 14.0213C20.8825 14.0213 20.3188 14.4062 20.0988 14.9838C20.0806 15.0292 20.0624 15.0753 20.0441 15.1218C19.9792 15.2863 19.9125 15.4555 19.8375 15.6163C19.5763 16.18 19.7 16.84 20.14 17.28C20.7313 17.8575 20.7313 18.8062 20.14 19.3975L19.3975 20.14C18.82 20.7313 17.8713 20.7313 17.28 20.14C16.8538 19.7 16.18 19.5763 15.6163 19.8375C15.41 19.9338 15.2037 20.0163 14.9838 20.0988C14.4062 20.3188 14.0213 20.8825 14.0213 21.5013C14.0213 22.3263 13.3475 23 12.5225 23H11.4775C10.6525 23 9.97875 22.3263 9.97875 21.5013C9.97875 20.8825 9.59375 20.3188 9.01625 20.0988C8.97079 20.0806 8.92466 20.0624 8.87815 20.044C8.71368 19.9792 8.54454 19.9125 8.38375 19.8375C7.82 19.5763 7.16 19.7 6.72 20.14C6.1425 20.7313 5.19375 20.7313 4.6025 20.14L3.86 19.3975C3.26875 18.82 3.26875 17.8713 3.86 17.28C4.3 16.8538 4.42375 16.18 4.1625 15.6163C4.06625 15.41 3.98375 15.2037 3.90125 14.9838C3.68125 14.4062 3.1175 14.0213 2.49875 14.0213C1.67375 14.0213 1 13.3475 1 12.5225V11.4775C1 10.6525 1.67375 9.97875 2.49875 9.97875C3.1175 9.97875 3.68125 9.59375 3.90125 9.01625C3.94464 8.87742 3.99897 8.74406 4.0539 8.60926C4.086 8.53046 4.11831 8.45117 4.14875 8.37C4.41 7.80625 4.28625 7.14625 3.84625 6.70625C3.255 6.12875 3.255 5.18 3.84625 4.58875L4.6025 3.86C5.18 3.26875 6.12875 3.26875 6.72 3.86C7.14625 4.3 7.82 4.42375 8.38375 4.1625C8.59 4.06625 8.79625 3.97 9.01625 3.90125C9.59375 3.68125 9.97875 3.1175 9.97875 2.49875C9.97875 1.67375 10.6525 1 11.4775 1H12.5225C13.3475 1 14.0213 1.67375 14.0213 2.49875C14.0213 3.13125 14.4062 3.68125 14.9838 3.90125C15.0292 3.91943 15.0753 3.93762 15.1218 3.95595C15.2863 4.02079 15.4555 4.08746 15.6163 4.1625C16.18 4.42375 16.84 4.3 17.28 3.86C17.8575 3.26875 18.8062 3.26875 19.3975 3.86L20.14 4.6025C20.7313 5.18 20.7313 6.12875 20.14 6.72C19.7 7.14625 19.5763 7.82 19.8375 8.38375C19.9338 8.59 20.0163 8.79625 20.0988 9.01625ZM12 17.5C8.96125 17.5 6.5 15.0387 6.5 12C6.5 8.96125 8.96125 6.5 12 6.5C15.0387 6.5 17.5 8.96125 17.5 12C17.5 15.0387 15.0387 17.5 12 17.5Z" fill="#ffffff"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View file

@ -158,3 +158,11 @@ details > :not(summary) {
details[open] > summary {
margin-bottom: 16px;
}
*[data-overlay-container] {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
}

View file

@ -337,6 +337,23 @@
"@react-aria/utils" "^3.10.0"
"@react-types/shared" "^3.10.0"
"@react-aria/menu@^3.3.0":
version "3.3.0"
resolved "https://registry.yarnpkg.com/@react-aria/menu/-/menu-3.3.0.tgz#09364a306b3b0dec7f3cf532bfa184a1f4e26da7"
integrity sha512-e/5zlWSwcsUYxH+kLrACPhLxh/Z+8/xvAB90G7xjBble1RusYQ+iH+M2U1n5vqoenZ3vjBpmEDsdo6vHeFeKxQ==
dependencies:
"@babel/runtime" "^7.6.2"
"@react-aria/interactions" "^3.7.0"
"@react-aria/overlays" "^3.7.3"
"@react-aria/selection" "^3.7.0"
"@react-aria/utils" "^3.10.0"
"@react-stately/collections" "^3.3.3"
"@react-stately/menu" "^3.2.3"
"@react-stately/tree" "^3.2.0"
"@react-types/button" "^3.4.1"
"@react-types/menu" "^3.3.0"
"@react-types/shared" "^3.10.0"
"@react-aria/overlays@^3.7.3":
version "3.7.3"
resolved "https://registry.yarnpkg.com/@react-aria/overlays/-/overlays-3.7.3.tgz#b107b1d31c04c538355e566b1034d23e5696c18a"
@ -352,6 +369,20 @@
"@react-types/overlays" "^3.5.1"
dom-helpers "^3.3.1"
"@react-aria/selection@^3.7.0":
version "3.7.0"
resolved "https://registry.yarnpkg.com/@react-aria/selection/-/selection-3.7.0.tgz#77dc483dca82303f20b8567bfac24a2e57bade6d"
integrity sha512-OHvxxTZeI8vJYQXDG9KUx/MFJ2DY70phW0XausbzYzUFwaXiWIOb8YQrTHA2CpVOV8E4c+qd522sxHGBq8hPDg==
dependencies:
"@babel/runtime" "^7.6.2"
"@react-aria/focus" "^3.5.0"
"@react-aria/i18n" "^3.3.3"
"@react-aria/interactions" "^3.7.0"
"@react-aria/utils" "^3.10.0"
"@react-stately/collections" "^3.3.3"
"@react-stately/selection" "^3.8.0"
"@react-types/shared" "^3.10.0"
"@react-aria/ssr@^3.0.3", "@react-aria/ssr@^3.1.0":
version "3.1.0"
resolved "https://registry.yarnpkg.com/@react-aria/ssr/-/ssr-3.1.0.tgz#b7163e6224725c30121932a8d1422ef91d1fab22"
@ -425,6 +456,25 @@
"@react-spring/shared" "~9.2.0"
"@react-spring/types" "~9.2.0"
"@react-stately/collections@^3.3.3", "@react-stately/collections@^3.3.4":
version "3.3.4"
resolved "https://registry.yarnpkg.com/@react-stately/collections/-/collections-3.3.4.tgz#ca9e481d2769dbebb593d5a1ed4bcc54013aef9d"
integrity sha512-HnlQip9RH+3nGNh8U2U1YkCdA+zGSedQLWVCdR53w/n6To7kIp7yDLby5dkmP+9VGQEkyfsoSjwGJ1NF94CCZg==
dependencies:
"@babel/runtime" "^7.6.2"
"@react-types/shared" "^3.8.0"
"@react-stately/menu@^3.2.3":
version "3.2.3"
resolved "https://registry.yarnpkg.com/@react-stately/menu/-/menu-3.2.3.tgz#eb58e3cfc941d49637bac04aa474935f08bc7215"
integrity sha512-r09qH8F+OaH7PTc9t2iAOfeCPy3jSg9uAwlDiGaev3zknM618XafIoQ1sWUNQYecSQ5BWWUyBYh5Vl8i2HnEvw==
dependencies:
"@babel/runtime" "^7.6.2"
"@react-stately/overlays" "^3.1.3"
"@react-stately/utils" "^3.2.2"
"@react-types/menu" "^3.3.0"
"@react-types/shared" "^3.8.0"
"@react-stately/overlays@^3.1.3":
version "3.1.3"
resolved "https://registry.yarnpkg.com/@react-stately/overlays/-/overlays-3.1.3.tgz#b0bb4061c1b20e712dfc32c933ae4bb23e5ccc0e"
@ -434,6 +484,16 @@
"@react-stately/utils" "^3.2.2"
"@react-types/overlays" "^3.5.1"
"@react-stately/selection@^3.7.0", "@react-stately/selection@^3.8.0":
version "3.8.0"
resolved "https://registry.yarnpkg.com/@react-stately/selection/-/selection-3.8.0.tgz#c5292d9b0e67cb48b1bfabd050da57949950e431"
integrity sha512-FDO2kJRTF43wxx6DD8fQtxCg7UvUtwO4KJi6hk/W7ZOyQZuwq9INQux826mvSXT7Ixw1OTkvKowrO6/knol0mA==
dependencies:
"@babel/runtime" "^7.6.2"
"@react-stately/collections" "^3.3.3"
"@react-stately/utils" "^3.3.0"
"@react-types/shared" "^3.10.0"
"@react-stately/toggle@^3.2.3":
version "3.2.3"
resolved "https://registry.yarnpkg.com/@react-stately/toggle/-/toggle-3.2.3.tgz#a4de6edc16982990492c6c557e5194f46dacc809"
@ -444,6 +504,17 @@
"@react-types/checkbox" "^3.2.3"
"@react-types/shared" "^3.8.0"
"@react-stately/tree@^3.2.0":
version "3.2.0"
resolved "https://registry.yarnpkg.com/@react-stately/tree/-/tree-3.2.0.tgz#151c90f161c5c8339b6876f59a4f0502be08670b"
integrity sha512-FfHfs79KeXN0Yi8X5O/oRWL1ZTZByhIT++NEUX4aCO3VSxnqhcl9/ErSmH/fYr36q0xdYZsX3BFvk/fm1EDkXQ==
dependencies:
"@babel/runtime" "^7.6.2"
"@react-stately/collections" "^3.3.3"
"@react-stately/selection" "^3.7.0"
"@react-stately/utils" "^3.2.2"
"@react-types/shared" "^3.8.0"
"@react-stately/utils@^3.2.2", "@react-stately/utils@^3.3.0":
version "3.3.0"
resolved "https://registry.yarnpkg.com/@react-stately/utils/-/utils-3.3.0.tgz#99866c5788539268a06035acd5925b25bb4cedde"
@ -473,6 +544,14 @@
"@react-types/overlays" "^3.5.1"
"@react-types/shared" "^3.8.0"
"@react-types/menu@^3.3.0":
version "3.4.1"
resolved "https://registry.yarnpkg.com/@react-types/menu/-/menu-3.4.1.tgz#42f58ce3b79b844441627c5cd3126705b3b00063"
integrity sha512-9xx7x13h2/DpnD8m2+eN09ViEwXldYXGtD0WSExO99ZulNi4tbzwJfnUBBJWj1aq9v2ZgObECOSqwkIDOJo6qA==
dependencies:
"@react-types/overlays" "^3.5.1"
"@react-types/shared" "^3.9.0"
"@react-types/overlays@^3.5.1":
version "3.5.1"
resolved "https://registry.yarnpkg.com/@react-types/overlays/-/overlays-3.5.1.tgz#35350dfca639d04a8fbd973de59b141450df1b46"