fix(ui): some design review fixes
This commit is contained in:
parent
cce7a7bdad
commit
d3ea2ce3d6
9 changed files with 158 additions and 45 deletions
|
|
@ -30,7 +30,7 @@ function Assist(props: Props) {
|
|||
active={isAssist}
|
||||
id="menu-assist"
|
||||
title="Live Sessions"
|
||||
iconName="play-circle-light"
|
||||
iconName="play-circle-bold"
|
||||
onClick={() => redirect(assist())}
|
||||
/>
|
||||
<SideMenuitem
|
||||
|
|
|
|||
|
|
@ -0,0 +1,103 @@
|
|||
import { useObserver } from 'mobx-react-lite';
|
||||
import React from 'react';
|
||||
import { Button, Modal, Form, Icon, Checkbox, Input } from 'UI';
|
||||
|
||||
interface Props {
|
||||
show: boolean;
|
||||
title: string;
|
||||
closeHandler?: () => void;
|
||||
onSave: (title: string) => void;
|
||||
}
|
||||
function EditRecordingModal(props: Props) {
|
||||
const { show, closeHandler, title, onSave } = props;
|
||||
const [text, setText] = React.useState(title)
|
||||
|
||||
React.useEffect(() => {
|
||||
const handleEsc = (e: any) => e.key === 'Escape' && closeHandler?.()
|
||||
document.addEventListener("keydown", handleEsc, false);
|
||||
return () => {
|
||||
document.removeEventListener("keydown", handleEsc, false);
|
||||
}
|
||||
}, [])
|
||||
|
||||
const write = ({ target: { value, name } }: any) => setText(value)
|
||||
|
||||
const save = () => {
|
||||
onSave(text)
|
||||
}
|
||||
return useObserver(() => (
|
||||
<Modal open={ show } onClose={closeHandler}>
|
||||
<Modal.Header className="flex items-center justify-between">
|
||||
<div>{ 'Edit Recording' }</div>
|
||||
<div onClick={ closeHandler }>
|
||||
<Icon
|
||||
color="gray-dark"
|
||||
size="14"
|
||||
name="close"
|
||||
/>
|
||||
</div>
|
||||
</Modal.Header>
|
||||
|
||||
<Modal.Content>
|
||||
<Form onSubmit={save}>
|
||||
<Form.Field>
|
||||
<label>{'Title:'}</label>
|
||||
<Input
|
||||
className=""
|
||||
name="name"
|
||||
value={ text }
|
||||
onChange={write}
|
||||
placeholder="Title"
|
||||
maxLength={100}
|
||||
autoFocus
|
||||
/>
|
||||
</Form.Field>
|
||||
|
||||
{/* <Form.Field>
|
||||
<label>{'Description:'}</label>
|
||||
<Input
|
||||
className=""
|
||||
type="textarea"
|
||||
name="description"
|
||||
value={ dashboard.description }
|
||||
onChange={write}
|
||||
placeholder="Description"
|
||||
maxLength={300}
|
||||
autoFocus={!focusTitle}
|
||||
/>
|
||||
</Form.Field>
|
||||
|
||||
<Form.Field>
|
||||
<div className="flex items-center">
|
||||
<Checkbox
|
||||
name="isPublic"
|
||||
className="font-medium mr-3"
|
||||
type="checkbox"
|
||||
checked={ dashboard.isPublic }
|
||||
onClick={ () => dashboard.update({ 'isPublic': !dashboard.isPublic }) }
|
||||
/>
|
||||
<div className="flex items-center cursor-pointer" onClick={ () => dashboard.update({ 'isPublic': !dashboard.isPublic }) }>
|
||||
<Icon name="user-friends" size="16" />
|
||||
<span className="ml-2"> Team can see and edit the dashboard.</span>
|
||||
</div>
|
||||
</div>
|
||||
</Form.Field> */}
|
||||
</Form>
|
||||
</Modal.Content>
|
||||
<Modal.Footer>
|
||||
<div className="-mx-2 px-2">
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={ save }
|
||||
className="float-left mr-2"
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
<Button className="mr-2" onClick={ closeHandler }>{ 'Cancel' }</Button>
|
||||
</div>
|
||||
</Modal.Footer>
|
||||
</Modal>
|
||||
));
|
||||
}
|
||||
|
||||
export default EditRecordingModal;
|
||||
|
|
@ -28,11 +28,11 @@ function RecordingsList() {
|
|||
show={lenth === 0}
|
||||
title={
|
||||
<div className="flex flex-col items-center justify-center">
|
||||
<Icon name="camera-video-off" size={80} color="figmaColors-accent-secondary" />
|
||||
<Icon name="no-recordings" size={80} color="figmaColors-accent-secondary" />
|
||||
<div className="text-center text-gray-600 my-4">
|
||||
{recordsSearch !== ''
|
||||
? 'No matching results'
|
||||
: "You haven't created any recordings yet"}
|
||||
: "No recordings available yet."}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
|
@ -40,7 +40,7 @@ function RecordingsList() {
|
|||
<div className="mt-3 border-b">
|
||||
<div className="grid grid-cols-12 py-2 font-medium px-6">
|
||||
<div className="col-span-8">Name</div>
|
||||
<div className="col-span-4">By</div>
|
||||
<div className="col-span-4">Last Modified</div>
|
||||
</div>
|
||||
|
||||
{sliceListPerPage(list, recordingsStore.page - 1, recordingsStore.pageSize).map(
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { IRecord } from 'App/services/RecordingsService';
|
|||
import { useStore } from 'App/mstore';
|
||||
import { toast } from 'react-toastify';
|
||||
import cn from 'classnames';
|
||||
import EditRecordingModal from './EditRecordingModal'
|
||||
|
||||
interface Props {
|
||||
record: IRecord;
|
||||
|
|
@ -39,12 +40,13 @@ function RecordsListItem(props: Props) {
|
|||
});
|
||||
};
|
||||
|
||||
const menuItems = [{ icon: 'trash', text: 'Delete', onClick: onDelete }];
|
||||
const menuItems = [{ icon: 'pencil', text: 'Rename', onClick: () => setEdit(true) }, { icon: 'trash', text: 'Delete', onClick: onDelete }];
|
||||
|
||||
const onSave = () => {
|
||||
const onSave = (title: string) => {
|
||||
recordingsStore
|
||||
.updateRecordingName(record.recordId, recordingTitle)
|
||||
.updateRecordingName(record.recordId, title)
|
||||
.then(() => {
|
||||
setRecordingTitle(title)
|
||||
toast.success('Recording name updated');
|
||||
})
|
||||
.catch(() => toast.error("Couldn't update recording name"));
|
||||
|
|
@ -53,45 +55,26 @@ function RecordsListItem(props: Props) {
|
|||
|
||||
return (
|
||||
<div className="hover:bg-active-blue border-t px-6">
|
||||
<EditRecordingModal show={isEdit} title={record.name} onSave={onSave} />
|
||||
<div className="grid grid-cols-12 py-4 select-none items-center">
|
||||
<div className="col-span-8 flex items-start">
|
||||
<div className="col-span-8 flex items-start" onClick={onRecordClick}>
|
||||
<div className="flex items-center capitalize-first">
|
||||
<div className="w-9 h-9 rounded-full bg-tealx-lightest flex items-center justify-center mr-2">
|
||||
<Icon name="camera-video" size="16" color="tealx" />
|
||||
</div>
|
||||
<div className="flex flex-col">
|
||||
{isEdit ? (
|
||||
<input
|
||||
ref={inputRef}
|
||||
name="recordName"
|
||||
placeholder="Recording name"
|
||||
autoFocus
|
||||
style={{ minWidth: 200 }}
|
||||
className="rounded fluid border-0 -mx-2 px-2 -mt-1"
|
||||
value={recordingTitle}
|
||||
onChange={(e) => setRecordingTitle(e.target.value)}
|
||||
onBlur={onSave}
|
||||
onFocus={() => setEdit(true)}
|
||||
/>
|
||||
) : (
|
||||
<Tooltip delay={200} title="Double click to rename">
|
||||
<div
|
||||
onDoubleClick={() => setEdit(true)}
|
||||
className={cn(
|
||||
'border-dotted border-gray-medium',
|
||||
'pt-1 w-fit -mt-2',
|
||||
'cursor-pointer select-none border-b'
|
||||
)}
|
||||
>
|
||||
{recordingTitle}
|
||||
</div>
|
||||
</Tooltip>
|
||||
)}
|
||||
<div
|
||||
className={cn(
|
||||
'pt-1 w-fit -mt-2',
|
||||
)}
|
||||
>
|
||||
{recordingTitle}
|
||||
</div>
|
||||
<div className="text-gray-medium text-sm">{durationFromMs(record.duration)}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-span-2">
|
||||
<div className="col-span-2" onClick={onRecordClick}>
|
||||
<div className="flex flex-col">
|
||||
<div>{record.createdBy}</div>
|
||||
<div className="text-gray-medium text-sm">
|
||||
|
|
@ -113,7 +96,9 @@ function RecordsListItem(props: Props) {
|
|||
/>
|
||||
<div>Play Video</div>
|
||||
</div>
|
||||
<ItemMenu bold items={menuItems} />
|
||||
<div className="hover:border-teal border border-transparent rounded-full">
|
||||
<ItemMenu bold items={menuItems} sm />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ interface Props {
|
|||
flat?: boolean;
|
||||
items: Item[];
|
||||
label?: React.ReactNode;
|
||||
sm?: boolean;
|
||||
onToggle?: (args: any) => void;
|
||||
}
|
||||
|
||||
|
|
@ -52,7 +53,7 @@ export default class ItemMenu extends React.PureComponent<Props> {
|
|||
};
|
||||
|
||||
render() {
|
||||
const { items, label = '', bold } = this.props;
|
||||
const { items, label = '', bold, sm } = this.props;
|
||||
const { displayed } = this.state;
|
||||
const parentStyles = label ? 'rounded px-2 py-2 hover:bg-gray-light' : '';
|
||||
|
||||
|
|
@ -61,9 +62,6 @@ export default class ItemMenu extends React.PureComponent<Props> {
|
|||
render={() => (
|
||||
<div
|
||||
className={cn(styles.menu, { [styles.menuDim]: !bold })}
|
||||
// style={{
|
||||
// top: this.props.flat ? 24 : undefined,
|
||||
// }}
|
||||
// data-displayed={displayed}
|
||||
>
|
||||
{items
|
||||
|
|
@ -111,7 +109,8 @@ export default class ItemMenu extends React.PureComponent<Props> {
|
|||
}}
|
||||
className={cn('rounded-full flex items-center justify-center', {
|
||||
'bg-gray-light': displayed,
|
||||
'w-10 h-10': !label,
|
||||
'w-10 h-10': !label && !sm,
|
||||
'w-8 h-8': sm,
|
||||
})}
|
||||
role="button"
|
||||
>
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
20
frontend/app/svg/icons/no-recordings.svg
Normal file
20
frontend/app/svg/icons/no-recordings.svg
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<svg viewBox="0 0 250 100" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="250" height="100" rx="13.1579" fill="#3EAAAF" fill-opacity="0.08"/>
|
||||
<rect opacity="0.6" x="86.8421" y="28.579" width="138.158" height="14.4737" rx="6.57895" fill-opacity="0.5"/>
|
||||
<rect opacity="0.3" x="86.8421" y="55.579" width="38.1579" height="14.4737" rx="6.57895" fill-opacity="0.5"/>
|
||||
<rect opacity="0.3" x="129.842" y="55.579" width="18.1579" height="14.4737" rx="6.57895" fill-opacity="0.5"/>
|
||||
<g clip-path="url(#clip0_101_7)">
|
||||
<path d="M46 73.625C39.7343 73.625 33.7251 71.1359 29.2946 66.7054C24.8641 62.2748 22.375 56.2657 22.375 50C22.375 43.7343 24.8641 37.7251 29.2946 33.2946C33.7251 28.8641 39.7343 26.375 46 26.375C52.2657 26.375 58.2748 28.8641 62.7054 33.2946C67.1359 37.7251 69.625 43.7343 69.625 50C69.625 56.2657 67.1359 62.2748 62.7054 66.7054C58.2748 71.1359 52.2657 73.625 46 73.625ZM46 77C53.1608 77 60.0284 74.1554 65.0919 69.0919C70.1554 64.0284 73 57.1608 73 50C73 42.8392 70.1554 35.9716 65.0919 30.9081C60.0284 25.8446 53.1608 23 46 23C38.8392 23 31.9716 25.8446 26.9081 30.9081C21.8446 35.9716 19 42.8392 19 50C19 57.1608 21.8446 64.0284 26.9081 69.0919C31.9716 74.1554 38.8392 77 46 77V77Z" fill-opacity="0.5"/>
|
||||
<g clip-path="url(#clip1_101_7)">
|
||||
<path d="M56.125 50C56.125 52.6853 55.0583 55.2607 53.1595 57.1595C51.2607 59.0583 48.6853 60.125 46 60.125C43.3147 60.125 40.7394 59.0583 38.8405 57.1595C36.9417 55.2607 35.875 52.6853 35.875 50C35.875 47.3147 36.9417 44.7394 38.8405 42.8405C40.7394 40.9417 43.3147 39.875 46 39.875C48.6853 39.875 51.2607 40.9417 53.1595 42.8405C55.0583 44.7394 56.125 47.3147 56.125 50V50ZM42.6512 45.7551C42.5323 45.6363 42.3712 45.5695 42.2031 45.5695C42.0351 45.5695 41.8739 45.6363 41.7551 45.7551C41.6363 45.8739 41.5695 46.0351 41.5695 46.2031C41.5695 46.3712 41.6363 46.5323 41.7551 46.6512L45.1052 50L41.7551 53.3488C41.6963 53.4077 41.6496 53.4775 41.6177 53.5544C41.5859 53.6313 41.5695 53.7137 41.5695 53.7969C41.5695 53.8801 41.5859 53.9625 41.6177 54.0393C41.6496 54.1162 41.6963 54.1861 41.7551 54.2449C41.8739 54.3637 42.0351 54.4305 42.2031 54.4305C42.2863 54.4305 42.3687 54.4141 42.4456 54.3823C42.5225 54.3504 42.5923 54.3037 42.6512 54.2449L46 50.8948L49.3488 54.2449C49.4077 54.3037 49.4775 54.3504 49.5544 54.3823C49.6313 54.4141 49.7137 54.4305 49.7969 54.4305C49.8801 54.4305 49.9625 54.4141 50.0393 54.3823C50.1162 54.3504 50.1861 54.3037 50.2449 54.2449C50.3037 54.1861 50.3504 54.1162 50.3823 54.0393C50.4141 53.9625 50.4305 53.8801 50.4305 53.7969C50.4305 53.7137 50.4141 53.6313 50.3823 53.5544C50.3504 53.4775 50.3037 53.4077 50.2449 53.3488L46.8948 50L50.2449 46.6512C50.3037 46.5923 50.3504 46.5225 50.3823 46.4456C50.4141 46.3687 50.4305 46.2863 50.4305 46.2031C50.4305 46.1199 50.4141 46.0375 50.3823 45.9607C50.3504 45.8838 50.3037 45.8139 50.2449 45.7551C50.1861 45.6963 50.1162 45.6496 50.0393 45.6177C49.9625 45.5859 49.8801 45.5695 49.7969 45.5695C49.7137 45.5695 49.6313 45.5859 49.5544 45.6177C49.4775 45.6496 49.4077 45.6963 49.3488 45.7551L46 49.1052L42.6512 45.7551Z" fill-opacity="0.5"/>
|
||||
</g>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_101_7">
|
||||
<rect width="54" height="54" fill="white" transform="translate(19 23)"/>
|
||||
</clipPath>
|
||||
<clipPath id="clip1_101_7">
|
||||
<rect width="20.25" height="20.25" fill="white" transform="translate(35.875 39.875)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.3 KiB |
4
frontend/app/svg/icons/play-circle-bold.svg
Normal file
4
frontend/app/svg/icons/play-circle-bold.svg
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
|
||||
<path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"/>
|
||||
<path d="M6.271 5.055a.5.5 0 0 1 .52.038l3.5 2.5a.5.5 0 0 1 0 .814l-3.5 2.5A.5.5 0 0 1 6 10.5v-5a.5.5 0 0 1 .271-.445z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 276 B |
|
|
@ -5,7 +5,7 @@ import type { ButtonOptions, ConfirmWindowOptions, } from './ConfirmWindow.js'
|
|||
const TEXT_GRANT_REMORTE_ACCESS = 'Grant Remote Control'
|
||||
const TEXT_REJECT = 'Reject'
|
||||
const TEXT_ANSWER_CALL = `${acceptCall}   Answer`
|
||||
const TEXT_ACCEPT_RECORDING = 'Accept recording'
|
||||
const TEXT_ACCEPT_RECORDING = 'Allow Recording'
|
||||
|
||||
export type Options = string | Partial<ConfirmWindowOptions>;
|
||||
|
||||
|
|
@ -47,5 +47,5 @@ export const recordRequestDefault = (opts: Options) =>
|
|||
opts,
|
||||
TEXT_ACCEPT_RECORDING,
|
||||
TEXT_REJECT,
|
||||
'Agent requested to record the video of this session. Allow?'
|
||||
'Agent requested to record activity in this browser tab.'
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue