Commit e389ada7 by Sergey

add screencust and videocam recording (audio not working)

parent 1625d42a
......@@ -75,6 +75,7 @@
"rc-upload": "^4.3.3",
"react": "^17.0.2",
"react-media-recorder": "^1.6.6",
"react-stopwatch": "^2.0.4",
"react-webcam": "^7.0.1",
"sass": "^1.49.9"
}
......
......@@ -25,10 +25,10 @@ import Video from './extensions/Video'
import Iframe from './extensions/Iframe'
import CustomLink from './extensions/CustomLink'
import DragAndDrop from "./extensions/DragAndDrop";
import Webcamera from "./extensions/Webcamera";
//import Formula from './extensions/Formula'
import { useReactMediaRecorder } from "react-media-recorder";
import axios from "axios";
import ReactStopwatch from 'react-stopwatch';
import VoiceMessage from "./extensions/VoiceMessage";
const initialBubbleItems = ['bold', 'italic', 'underline', 'strike', '|', 'colorText', 'highlight'];
......@@ -46,13 +46,13 @@ const QEditor = ({ value, onChange = ()=>{}, style, uploadOptions, toolsOptions
const [focusFromTo, setFocusFromTo] = useState(null);
const [oldFocusFromTo, setOldFocusFromTo] = useState(null);
const [isUploading, setIsUploading] = useState(false);
const [recordType, setRecordType] = useState({screen: true})
const getRgb = (hex) => {
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result ? `rgb(${parseInt(result[1], 16)}, ${parseInt(result[2], 16)}, ${parseInt(result[3], 16)})` : null;
}
const { status, startRecording, stopRecording, mediaBlobUrl, previewStream, muteAudio, unMuteAudio, isAudioMuted, clearBlobUrl } = useReactMediaRecorder({ screen: true });
const [isRecord, setIsRecord] = useState(false);
const { status, startRecording, stopRecording, mediaBlobUrl, previewStream, muteAudio, unMuteAudio, isAudioMuted, clearBlobUrl } = useReactMediaRecorder(recordType);
const videoRef = useRef(null);
......@@ -69,14 +69,6 @@ const QEditor = ({ value, onChange = ()=>{}, style, uploadOptions, toolsOptions
}
}, [focusFromTo])
useEffect(() => {
if (status === "recording" || status === "acquiring_media") {
setIsRecord(true)
} else if (status === "stopped"){
setIsRecord(false)
}
}, [status])
const modalOpener = (type, title) => {
setModalTitle(title);
setInnerModalType(type);
......@@ -148,10 +140,6 @@ const QEditor = ({ value, onChange = ()=>{}, style, uploadOptions, toolsOptions
title: 'Загрузить видео',
onClick: () => modalOpener('video', 'Загрузить видео')
},
webcamera: {
title: 'Записать экран',
onClick: () => modalOpener('webcamera', 'Записать экран')
},
iframe: {
title: 'Видео по ссылке',
onClick: () => modalOpener('iframe', 'Видео по ссылке')
......@@ -300,6 +288,27 @@ const QEditor = ({ value, onChange = ()=>{}, style, uploadOptions, toolsOptions
title: 'Цвет фона',
onClick: () => setColorsSelected('highlight')
},
voicemessage: {
title: 'Записать голосовое сообщение',
onClick: () => {
modalOpener('voicemessage', 'Записать голосовое сообщение')
setRecordType({audio: true})
}
},
webcamera: {
title: 'Записать с камеры',
onClick: () => {
modalOpener('webcamera', 'Записать с камеры')
setRecordType({video: true})
}
},
screencust: {
title: 'Записать экран',
onClick: () => {
modalOpener('screencust', 'Записать экран')
setRecordType({screen: true})
}
},
// katex: {
// title: 'Вставить формулу',
// onClick: () => {
......@@ -356,7 +365,7 @@ const QEditor = ({ value, onChange = ()=>{}, style, uploadOptions, toolsOptions
DragAndDrop.configure({
linkUpload: uploadOptions.url
}),
Webcamera
VoiceMessage
],
content: value,
onUpdate: ({editor}) => onChange(editor.getHTML()),
......@@ -427,23 +436,22 @@ const QEditor = ({ value, onChange = ()=>{}, style, uploadOptions, toolsOptions
}
const saveScreenCust = async (fileBlob) => {
console.log(fileBlob);
setIsUploading(true)
let blobData = await fetch(fileBlob).then((res) => res.blob());
const data = new FormData();
let file = new File([blobData], "name.mp4");
data.append("file", file);
console.log(blobData);
const headers = {'Content-Type': 'multipart/form-data'};
await axios.post(uploadOptions.url, data, {headers: headers} ).then(response => {
if (response.data.state === "success"){
console.log(response.data);
setUploadedPaths(response.data)
}
setIsUploading(false)
});
if (fileBlob) {
setIsUploading(true)
let blobData = await fetch(fileBlob).then((res) => res.blob());
const data = new FormData();
let file = new File([blobData], "name." + (recordType?.audio ? "mp3" : "webm"));
data.append("file", file);
const headers = {'Content-Type': 'multipart/form-data'};
await axios.post(uploadOptions.url, data, {headers: headers}).then(response => {
if (response.data.state === "success") {
setUploadedPaths(response.data)
}
setIsUploading(false)
});
}
};
const getInnerModal = () => {
......@@ -474,32 +482,147 @@ const QEditor = ({ value, onChange = ()=>{}, style, uploadOptions, toolsOptions
return (
<Fragment>{ getUploader({ accept: '*', afterParams: ['no_convert=1'] }) }</Fragment>
)
case 'voicemessage':
return (
<>
<Fragment>
<div className={"audio-player"}>
<div className={"audio-player-start audio-player-margin"}>
{
status === 'recording' && !mediaBlobUrl ?
<div onClick={stopRecording} className={"audio-player-center-recording"}/> :
<div onClick={startRecording} className={"audio-player-center-start"}/>
}
</div>
<div className={"audio-player-voice audio-player-margin"}/>
{
status === 'recording' && ! mediaBlobUrl ?
<ReactStopwatch
seconds={0}
minutes={0}
hours={0}
render={({formatted}) => {
return (
<span className={"audio-player-timer audio-player-margin"}>{formatted}</span>
)
}}
/> : <span className={"audio-player-timer audio-player-margin"} />
}
</div>
</Fragment>
</>
)
case 'screencust':
return (
<>
<Fragment>
<div className={"webwrap"}>
<div className={"webwrap-content"}>
{
mediaBlobUrl ?
<video className={"webwrap-video"} id={"id-video"} src={mediaBlobUrl} autoPlay controls /> : status === "recording" &&
<video className={"webwrap-video"} ref={videoRef} src={previewStream} autoPlay controls={false}/>
}
{
status === 'recording' && !mediaBlobUrl ?
<ReactStopwatch
seconds={0}
minutes={0}
hours={0}
render={({ formatted }) => {
return (
<span className={"webwrap-timer"}>
{formatted}
</span>
)
}}
/> : <span className={"webwrap-timer"}>00:00:00</span>
}
{
!mediaBlobUrl &&
<div className={"webwrap-start-border"}>
<button onClick={status === 'recording' ? stopRecording : startRecording} className={status === 'recording' ? "webwrap-record-center" : "webwrap-start-center"} />
</div>
}
</div>
</div>
<div className={"web-bottom-elements"}>
{ mediaBlobUrl &&
<div onClick={clearBlobUrl} className={"web-button-wrap"}>
<div className={"web-button-rerecord"}/>
<span className={"web-button-rerecord-text"}>Перезаписать</span>
</div>
}
{
mediaBlobUrl &&
<div onClick={() => saveScreenCust(mediaBlobUrl)} className={"web-button-wrap"}>
<span className={"web-button-rerecord-text"}>Сохранить</span>
</div>
}
{
!mediaBlobUrl &&
<div className={"web-button-spacer"}/>
}
{
!mediaBlobUrl &&
<div onClick={isAudioMuted ? unMuteAudio : muteAudio} className={isAudioMuted ? "web-button-unmute" : "web-button-mute"}/>
}
<div className={"web-button-spacer"}/>
</div>
</Fragment>
</>
)
case 'webcamera':
return (
<>
<Fragment>
<div className={"webwrap"}>
{
mediaBlobUrl ?
<video id={"id-video"} width={window.innerWidth / 2} height={window.innerHeight / 2} src={mediaBlobUrl} autoPlay controls /> : status === "recording" &&
<video ref={videoRef} width={window.innerWidth / 2} height={window.innerHeight / 2} src={previewStream} autoPlay controls={false} />
}
<div className={"btn-video-wrap"}>
<div className={"webwrap-content"}>
{
isRecord ?
<button className={"btn-video btn-video-stop"} onClick={stopRecording}>Остановить запись</button> : mediaBlobUrl ?
(<>
<button className={"btn-video btn-video-stop"} onClick={clearBlobUrl}>Перезаписать</button>
<button className={"btn-video btn-video-record "} style={{ backgroundColor: isUploading && "#AAB2BD" }} disabled={isUploading} onClick={() => saveScreenCust(mediaBlobUrl)}>{isUploading ? "Загрузка..." : "Сохранить запись"}</button>
</>) :
<button className={"btn-video btn-video-record"} onClick={startRecording}>Начать запись</button>
mediaBlobUrl ?
<video className={"webwrap-video"} id={"id-video"} src={mediaBlobUrl} autoPlay controls /> : status === "recording" &&
<video className={"webwrap-video"} ref={videoRef} src={previewStream} autoPlay controls={false}/>
}
{
isRecord &&
<button className={"btn-video btn-video-mute"} onClick={isAudioMuted ? unMuteAudio : muteAudio}>{isAudioMuted ? "Вернуть звук" : "Убрать звук"}</button>
status === 'recording' && !mediaBlobUrl ?
<ReactStopwatch
seconds={0}
minutes={0}
hours={0}
render={({ formatted }) => {
return (
<span className={"webwrap-timer"}>
{formatted}
</span>
)
}}
/> : <span className={"webwrap-timer"}>00:00:00</span>
}
{
!mediaBlobUrl &&
<div className={"webwrap-start-border"}>
<button onClick={status === 'recording' ? stopRecording : startRecording} className={status === 'recording' ? "webwrap-record-center" : "webwrap-start-center"} />
</div>
}
</div>
</div>
<div className={"web-bottom-elements"}>
{ mediaBlobUrl &&
<div onClick={clearBlobUrl} className={"web-button-wrap"}>
<div className={"web-button-rerecord"}/>
<span className={"web-button-rerecord-text"}>Перезаписать</span>
</div>
}
{
!mediaBlobUrl &&
<div className={"web-button-spacer"}/>
}
{
!mediaBlobUrl &&
<div onClick={isAudioMuted ? unMuteAudio : muteAudio} className={isAudioMuted ? "web-button-unmute" : "web-button-mute"}/>
}
<div className={"web-button-spacer"}/>
</div>
</Fragment>
</>
)
......@@ -633,95 +756,116 @@ const QEditor = ({ value, onChange = ()=>{}, style, uploadOptions, toolsOptions
onClick: () => {
setUploaderUid(`uid${new Date()}`);
setUploadedPaths([]);
setModalIsOpen(false)
setModalIsOpen(false);
clearBlobUrl()
}
},
{
title: 'Вставить',
title: (mediaBlobUrl && uploadedPaths.length === 0) ? (isUploading ? 'Сохранение...' : 'Сохранить') : 'Вставить',
className: ' atma-editor-complete',
onClick: () => {
if(document.querySelectorAll('.atma-editor-uploader-progress').length > 0){
if(!confirm('Не полностью загруженные файлы будут утеряны. Вы уверены, что хотите продолжить?')){
return false;
onClick: async () => {
if (mediaBlobUrl && uploadedPaths.length === 0){
if (!isUploading) {
await saveScreenCust(mediaBlobUrl);
}
}
try {
switch (innerModalType) {
case 'image':
uploadedPaths.map((file, i) => {
editor.chain().focus().setImage({ src: file.path }).run();
});
break
case 'video':
uploadedPaths.map((file, i) => {
editor.chain().focus().setVideo({ src: file.path, poster: file.path + '.jpg' }).run();
});
break
case 'webcamera':
editor.chain().focus().setVideo({ src: uploadedPaths.file_path }).run();
break
case 'iframe':
let _url = embedContent;
let reg = /(http|https):\/\/([\w.]+\/?)\S*/;
const url = new URL(reg.test(_url) ? _url : 'https:' + _url);
let urlId = url.pathname.replace(/\/$/ig, '').split('/').pop();
switch (url.hostname) {
case 'rutube.ru':
case 'www.rutube.ru':
_url = `https://rutube.ru/pl/?pl_id&pl_type&pl_video=${urlId}`;
break
case 'vimeo.com':
_url = `https://player.vimeo.com/video/${urlId}`;
break
case 'ok.ru':
case 'www.ok.ru':
_url = `//ok.ru/videoembed/${urlId}`;
break
case 'youtu.be':
case 'youtube.com':
case 'www.youtube.com':
if (url.hostname.indexOf('youtu.be') === -1 && url.search !== '') {
if (url.searchParams.get('v')) {
urlId = url.searchParams.get('v');
} else {
if (document.querySelectorAll('.atma-editor-uploader-progress').length > 0) {
if ( ! confirm('Не полностью загруженные файлы будут утеряны. Вы уверены, что хотите продолжить?')) {
return false;
}
}
try {
switch (innerModalType) {
case 'image':
uploadedPaths.map((file, i) => {
editor.chain().focus().setImage({src: file.path}).run();
});
break
case 'video':
uploadedPaths.map((file, i) => {
editor.chain().focus().setVideo({
src: file.path,
poster: file.path + '.jpg'
}).run();
});
break
case 'voicemessage':
if (uploadedPaths?.file_path) {
editor.commands.setVoiceMessage({ src: uploadedPaths.file_path })
}
break
case 'screencust':
if (uploadedPaths?.file_path) {
editor.chain().focus().setVideo({src: uploadedPaths.file_path}).run();
}
break
case 'webcamera':
if (uploadedPaths?.file_path) {
editor.chain().focus().setVideo({src: uploadedPaths.file_path}).run();
}
break
case 'iframe':
let _url = embedContent;
let reg = /(http|https):\/\/([\w.]+\/?)\S*/;
const url = new URL(reg.test(_url) ? _url : 'https:' + _url);
let urlId = url.pathname.replace(/\/$/ig, '').split('/').pop();
switch (url.hostname) {
case 'rutube.ru':
case 'www.rutube.ru':
_url = `https://rutube.ru/pl/?pl_id&pl_type&pl_video=${urlId}`;
break
case 'vimeo.com':
_url = `https://player.vimeo.com/video/${urlId}`;
break
case 'ok.ru':
case 'www.ok.ru':
_url = `//ok.ru/videoembed/${urlId}`;
break
case 'youtu.be':
case 'youtube.com':
case 'www.youtube.com':
if (url.hostname.indexOf('youtu.be') === -1 && url.search !== '') {
if (url.searchParams.get('v')) {
urlId = url.searchParams.get('v');
}
}
}
_url = `https://www.youtube.com/embed/${urlId}`;
break
}
editor.chain().focus().setIframe({ src: _url }).run();
_url = `https://www.youtube.com/embed/${urlId}`;
break
}
editor.chain().focus().setIframe({src: _url}).run();
break
case 'file':
break
case 'file':
console.log(uploadedPaths, 'ejkwnferiugnuierwnguirne');
console.log(uploadedPaths, 'ejkwnferiugnuierwnguirne');
uploadedPaths.map((file, i) => {
console.log(file);
uploadedPaths.map((file, i) => {
console.log(file);
editor
.chain().focus()
editor.chain().focus()
// .extendMarkRange('link').setLink({
// href: file.path,
// target: '_blank',
// download: true,
// 'data-size': file.size
// })
.insertContent(`<a href="${file.path}" target="_blank" download="true" data-size="${file.size}">${file.name}</a>`)
.run();
});
break
}
.insertContent(`<a href="${file.path}" target="_blank" download="true" data-size="${file.size}">${file.name}</a>`).run();
});
break
}
setUploaderUid(`uid${new Date()}`);
setEmbedContent('');
setUploadedPaths([]);
setModalTitle('');
setModalIsOpen(false);
}catch (err){
console.log(err)
setUploaderUid(`uid${new Date()}`);
setEmbedContent('');
setUploadedPaths([]);
setModalTitle('');
setModalIsOpen(false);
clearBlobUrl()
} catch (err) {
console.log(err)
}
}
},
disabled: isDisabledAction()
......
......@@ -52,12 +52,6 @@ const toolsInit = {
{
type: 'g',
items: [
'webcamera',
]
},
{
type: 'g',
items: [
'clearMarks',
'hardBreak',
]
......@@ -82,7 +76,14 @@ const toolsInit = {
'mergeOrSplit',
'deleteTable'
]
}
},
{
type: 'g',
items: [
'webcamera',
'screencust'
]
},
],
'text': [
{
......@@ -105,12 +106,6 @@ const toolsInit = {
{
type: 'g',
items: [
'webcamera',
]
},
{
type: 'g',
items: [
'bulletList',
'orderedList',
'blockquote',
......@@ -134,6 +129,13 @@ const toolsInit = {
'hardBreak',
]
},
{
type: 'g',
items: [
'webcamera',
'screencust'
]
},
]
}
......
......@@ -50,30 +50,21 @@ const DragAndDrop = Extension.create({
// }));
// console.log(hasFiles)
if (!hasFiles) {
if (hasFiles) {
event.preventDefault();
const images = event.dataTransfer.files;
const {schema} = view.state;
const coordinates = view.posAtCoords({left: event.clientX, top: event.clientY});
const transaction = view.state.tr.insert(coordinates.pos, schema.text(
event.dataTransfer.getData("text/plain")
));
view.dispatch(transaction)
return
}
event.preventDefault();
const images = event.dataTransfer.files;
const {schema} = view.state;
const coordinates = view.posAtCoords({left: event.clientX, top: event.clientY});
for (let i = 0; i < images.length; i++) {
const imageSrc = await upload(images[i]);
if (imageSrc) {
const node = schema.nodes.image.create({
src: imageSrc
});
const transaction = view.state.tr.insert(coordinates.pos, node);
view.dispatch(transaction)
for (let i = 0; i < images.length; i++) {
const imageSrc = await upload(images[i]);
if (imageSrc) {
const node = schema.nodes.image.create({
src: imageSrc
});
const transaction = view.state.tr.insert(coordinates.pos, node);
view.dispatch(transaction)
}
}
}
}
......
import React from 'react';
import { mergeAttributes, Node } from "@tiptap/core";
const VoiceMessage = Node.create({
addCommands() {
return {
setVoiceMessage: (options) => ({ chain }) => {
console.log(options)
return chain()
.insertContent('<h1>' + options.src + '</h1>')
.run()
},
}
}
});
export default VoiceMessage;
......@@ -7,57 +7,228 @@ body{
padding-bottom: 12px;
}
.webwrap {
.progress-btn {
background-color: #1790FF;
border-radius: 24px;
color: #AAB2BD;
}
.audio-player {
width: 100%;
height: 51px;
background-color: #E6F7FF;
border-radius: 51px;
display: flex;
justify-content: center;
justify-content: space-between;
align-items: center;
flex-direction: column;
}
.btn {
&-video {
border-radius: 66px;
width: 200px;
height: 50px;
&-start {
height: 33px;
width: 33px;
background-color: white;
border-radius: 100px;
display: flex;
justify-content: center;
align-items: center;
}
&-center-start {
width: 70%;
height: 70%;
background-color: #FF3B30;
border-radius: 100px;
cursor: pointer;
color: white;
margin: 5px;
}
&-center-recording {
width: 40%;
height: 40%;
background-color: #FF3B30;
border-radius: 2px;
cursor: pointer;
}
&-margin {
margin: 10px;
}
&-voice {
width: 70%;
border-bottom: 2px dotted #1790FF;
}
&-timer {
margin-right: 20px;
color: #1790FF;
}
}
.web {
&-bottom-elements {
display: flex;
flex-direction: row;
justify-content: space-between;
margin-top: 30px;
border: none;
font-size: 17px;
}
&:hover {
-webkit-box-shadow: 4px 4px 26px 12px rgba(34, 60, 80, 0.2);
-moz-box-shadow: 4px 4px 26px 12px rgba(34, 60, 80, 0.2);
box-shadow: 4px 4px 26px 12px rgba(34, 60, 80, 0.2);
}
&-button-wrap {
cursor: pointer;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
&-disabled {
background-color: #AAB2BD;
&-button-rerecord {
cursor: pointer;
width: 30px;
height: 30px;
background-image: url("data:image/svg+xml,%3Csvg width='30' height='30' viewBox='0 0 30 30' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cg clip-path='url(%23clip0_220_1498)'%3E%3Ccircle cx='15' cy='15' r='15' fill='%23AAB2BD'/%3E%3Cpath d='M9.16992 15.8948C9.16992 19.3059 11.918 22.0608 15.3223 22.0608C18.7334 22.0608 21.4814 19.3059 21.4814 15.8948C21.4814 12.4836 18.7676 9.76294 15.3633 9.76294C15.0557 9.76294 14.7549 9.79028 14.4951 9.84497L16.0195 8.34106C16.1494 8.19751 16.2246 8.03345 16.2246 7.82837C16.2246 7.41138 15.9033 7.06958 15.4863 7.06958C15.2744 7.06958 15.1035 7.14478 14.9668 7.29517L12.1641 10.1389C12.0137 10.2893 11.9316 10.4875 11.9316 10.6926C11.9316 10.9045 12.0068 11.0891 12.1641 11.2532L14.9668 14.0764C15.0967 14.2131 15.2744 14.2815 15.4863 14.2815C15.9033 14.2815 16.2246 13.9602 16.2246 13.5364C16.2246 13.3381 16.1494 13.1741 16.0127 13.0374L14.29 11.3284C14.6045 11.2668 14.9668 11.2395 15.3633 11.2395C17.9268 11.2395 19.957 13.2903 19.957 15.8948C19.957 18.4651 17.8994 20.5364 15.3223 20.5364C12.7588 20.5364 10.6875 18.4651 10.6875 15.8948C10.6875 15.4368 10.3867 15.1155 9.94922 15.1155C9.49121 15.1155 9.16992 15.4368 9.16992 15.8948Z' fill='white'/%3E%3C/g%3E%3Cdefs%3E%3CclipPath id='clip0_220_1498'%3E%3Crect width='30' height='30' fill='white'/%3E%3C/clipPath%3E%3C/defs%3E%3C/svg%3E");
&-text {
margin-left: 10px;
font-weight: 400;
font-size: 17px;
line-height: 20px;
text-align: center;
color: #AAB2BD;
}
}
&-wrap {
display: flex;
flex-direction: row;
}
&-button-mute {
cursor: pointer;
width: 36px;
height: 36px;
background-image: url("data:image/svg+xml,%3Csvg width='36' height='36' viewBox='0 0 36 36' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M17.85 4.5C15.0784 4.5 12.75 6.82843 12.75 9.6V15.45C12.75 18.2216 15.0784 20.55 17.85 20.55C20.8296 20.55 23.064 18.3294 22.9512 15.51C22.9504 15.49 22.95 15.47 22.95 15.45V9.6C22.95 6.82843 20.6216 4.5 17.85 4.5ZM9.75 9.6C9.75 5.17157 13.4216 1.5 17.85 1.5C22.2784 1.5 25.95 5.17157 25.95 9.6V15.4215C26.1191 20.0862 22.3603 23.55 17.85 23.55C13.4216 23.55 9.75 19.8784 9.75 15.45V9.6ZM6 13.95C6.82843 13.95 7.5 14.6216 7.5 15.45C7.5 21.2284 12.2275 25.9308 17.9659 25.8004L18 25.8C23.634 25.8 28.35 21.2092 28.35 15.45C28.35 14.6216 29.0216 13.95 29.85 13.95C30.6784 13.95 31.35 14.6216 31.35 15.45C31.35 22.4247 26.0042 28.0538 19.35 28.7315V33C19.35 33.8284 18.6785 34.5 17.85 34.5C17.0216 34.5 16.35 33.8284 16.35 33V28.7309C9.67992 28.0296 4.5 22.3045 4.5 15.45C4.5 14.6216 5.17157 13.95 6 13.95Z' fill='%23AAB2BD'/%3E%3C/svg%3E");
}
&-record {
background-color: #72c85f;
}
&-button-unmute {
cursor: pointer;
width: 36px;
height: 36px;
background-image: url("data:image/svg+xml,%3Csvg width='36' height='36' viewBox='0 0 36 36' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M17.85 4.5C15.0784 4.5 12.75 6.82843 12.75 9.6V15.45C12.75 18.2216 15.0784 20.55 17.85 20.55C20.8296 20.55 23.064 18.3294 22.9512 15.51C22.9504 15.49 22.95 15.47 22.95 15.45V9.6C22.95 6.82843 20.6216 4.5 17.85 4.5ZM9.75 9.6C9.75 5.17157 13.4216 1.5 17.85 1.5C22.2784 1.5 25.95 5.17157 25.95 9.6V15.4215C26.1191 20.0862 22.3603 23.55 17.85 23.55C13.4216 23.55 9.75 19.8784 9.75 15.45V9.6ZM6 13.95C6.82843 13.95 7.5 14.6216 7.5 15.45C7.5 21.2284 12.2275 25.9308 17.9659 25.8004L18 25.8C23.634 25.8 28.35 21.2092 28.35 15.45C28.35 14.6216 29.0216 13.95 29.85 13.95C30.6784 13.95 31.35 14.6216 31.35 15.45C31.35 22.4247 26.0042 28.0538 19.35 28.7315V33C19.35 33.8284 18.6785 34.5 17.85 34.5C17.0216 34.5 16.35 33.8284 16.35 33V28.7309C9.67992 28.0296 4.5 22.3045 4.5 15.45C4.5 14.6216 5.17157 13.95 6 13.95Z' fill='%23AAB2BD'/%3E%3Crect y='3.12558' width='3' height='45.1821' rx='1.5' transform='rotate(-45.1148 0 3.12558)' fill='%23FF5F56'/%3E%3C/svg%3E");
}
&-stop {
background-color: #EE505A;
}
&-button-spacer {
cursor: pointer;
width: 36px;
height: 36px;
}
}
&-mute {
background-color: #AAB2BD;
}
.webwrap {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
&-video {
width: 50vw;
height: 50vh;
}
&-start-border {
border: 3px solid white;
border-radius: 100px;
position: absolute;
bottom: 210px;
height: 70px;
width: 70px;
padding: 5px;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
z-index: 2;
}
&-timer {
position: absolute;
top: 120px;
font-weight: 400;
font-size: 21px;
line-height: 20px;
text-align: center;
color: #ffffff;
margin-top: 30px;
z-index: 2;
}
&-start-center {
width: 100%;
height: 100%;
background-color: #FF3B30;
border-radius: 100px;
border: none;
cursor: pointer;
z-index: 2;
}
&-record-center {
width: 65%;
height: 65%;
background-color: #FF3B30;
border-radius: 12px;
border: none;
cursor: pointer;
z-index: 2;
}
&-content {
width: 50vw;
height: 55vh;
background-color: black;
border-radius: 12px;
display: flex;
justify-content: center;
align-items: center;
}
}
//.btn {
// &-video {
// border-radius: 66px;
// width: 200px;
// height: 50px;
// display: flex;
// justify-content: center;
// align-items: center;
// cursor: pointer;
// color: white;
// margin: 5px;
// margin-top: 30px;
// border: none;
// font-size: 17px;
//
// &:hover {
// -webkit-box-shadow: 4px 4px 26px 12px rgba(34, 60, 80, 0.2);
// -moz-box-shadow: 4px 4px 26px 12px rgba(34, 60, 80, 0.2);
// box-shadow: 4px 4px 26px 12px rgba(34, 60, 80, 0.2);
// }
//
// &-disabled {
// background-color: #AAB2BD;
// }
//
// &-wrap {
// display: flex;
// flex-direction: row;
// }
//
// &-record {
// background-color: #72c85f;
// }
//
// &-stop {
// background-color: #EE505A;
// }
//
// &-mute {
// background-color: #AAB2BD;
// }
// }
//}
.atma-editor {
position: relative;
border-radius: 8px;
......@@ -787,10 +958,15 @@ body{
&.qfile{
background-image: url('data:image/svg+xml;charset=utf8,%3Csvg%20width%3D%229%22%20height%3D%2216%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M4.85%2015c-1.062%200-1.969-.365-2.721-1.094C1.376%2013.177%201%2012.282%201%2011.22V3.695c0-.747.265-1.382.796-1.908A2.627%202.627%200%200%201%203.713%201c.758%200%201.4.262%201.925.787.524.526.787%201.167.787%201.926v6.894c0%20.444-.152.82-.455%201.13-.303.308-.677.463-1.12.463-.443%200-.817-.166-1.12-.499a1.694%201.694%200%200%201-.455-1.181V4.01c0-.093.035-.175.105-.245a.336.336%200%200%201%20.49%200c.07.07.105.152.105.245v6.562c0%20.257.085.476.254.657.169.18.376.271.621.271a.83.83%200%200%200%20.621-.262.874.874%200%200%200%20.254-.63V3.694c0-.56-.195-1.033-.586-1.417A1.956%201.956%200%200%200%203.713%201.7c-.56%200-1.036.193-1.427.578-.39.384-.586.857-.586%201.417v7.56c0%20.852.31%201.572.928%202.161.618.59%201.359.884%202.222.884.875%200%201.619-.298%202.231-.893.613-.595.919-1.324.919-2.187V4.01c0-.093.035-.175.105-.245a.336.336%200%200%201%20.49%200c.07.07.105.152.105.245v7.192c0%201.062-.376%201.96-1.129%202.696C6.82%2014.632%205.911%2015%204.85%2015z%22%20fill%3D%22%231D1D1F%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%231D1D1F%22%20stroke-width%3D%22.5%22%2F%3E%3C%2Fsvg%3E');
}
&.qvoicemessage {
background-image: url("data:image/svg+xml,%3Csvg width='12' height='16' viewBox='0 0 12 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M5.93333 2.00001C4.70151 2.00001 3.66667 3.03486 3.66667 4.26667V6.86667C3.66667 8.09849 4.70151 9.13334 5.93333 9.13334C7.2576 9.13334 8.25067 8.14641 8.20053 6.89334C8.20018 6.88445 8.2 6.87556 8.2 6.86667V4.26667C8.2 3.03486 7.16516 2.00001 5.93333 2.00001ZM2.33333 4.26667C2.33333 2.29848 3.96516 0.666672 5.93333 0.666672C7.90151 0.666672 9.53333 2.29848 9.53333 4.26667V6.85401C9.60849 8.92721 7.93791 10.4667 5.93333 10.4667C3.96516 10.4667 2.33333 8.83485 2.33333 6.86667V4.26667ZM0.666667 6.20001C1.03486 6.20001 1.33333 6.49849 1.33333 6.86667C1.33333 9.43485 3.43444 11.5248 5.98485 11.4669L6 11.4667C8.504 11.4667 10.6 9.42632 10.6 6.86667C10.6 6.49849 10.8985 6.20001 11.2667 6.20001C11.6348 6.20001 11.9333 6.49849 11.9333 6.86667C11.9333 9.96654 9.55742 12.4684 6.6 12.7696V14.6667C6.6 15.0349 6.30156 15.3333 5.93333 15.3333C5.56516 15.3333 5.26667 15.0349 5.26667 14.6667V12.7693C2.30219 12.4576 0 9.91312 0 6.86667C0 6.49849 0.298476 6.20001 0.666667 6.20001Z' fill='%23151618'/%3E%3C/svg%3E");
}
&.qscreencust {
background-image: url("data:image/svg+xml,%3Csvg width='17' height='16' viewBox='0 0 17 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M8.075 1V0.925H8H3C1.85403 0.925 0.925 1.85403 0.925 3V11C0.925 12.146 1.85403 13.075 3 13.075H14C15.146 13.075 16.075 12.146 16.075 11V9V8.925H16H15H14.925V9V11C14.925 11.5109 14.5109 11.925 14 11.925H3C2.48911 11.925 2.075 11.5109 2.075 11V3C2.075 2.48911 2.48911 2.075 3 2.075H8H8.075V2V1ZM4.5 13.925C4.18246 13.925 3.925 14.1825 3.925 14.5C3.925 14.8175 4.18246 15.075 4.5 15.075H12.5C12.8175 15.075 13.075 14.8175 13.075 14.5C13.075 14.1825 12.8175 13.925 12.5 13.925H4.5ZM15.5 0.925H11C10.6825 0.925 10.425 1.18246 10.425 1.5C10.425 1.81754 10.6825 2.075 11 2.075H14.1118L9.09345 7.09339C8.86885 7.31799 8.86885 7.68201 9.09345 7.90661C9.31799 8.13115 9.68207 8.13115 9.90661 7.90661L14.925 2.88816V6C14.925 6.31754 15.1825 6.575 15.5 6.575C15.8176 6.575 16.075 6.31754 16.075 6V1.5C16.075 1.18246 15.8176 0.925 15.5 0.925Z' fill='%23151618' stroke='%23151618' stroke-width='0.15'/%3E%3C/svg%3E");
}
&.qwebcamera {
background-image: url('data:image/svg+xml;charset=utf8,%3Csvg%20width%3D%2214%22%20height%3D%2214%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cg%20transform%3D%22translate%281.107%20.622%29%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20stroke%3D%22%231F1E1D%22%20stroke-width%3D%221.2%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20width%3D%2212%22%20height%3D%2212%22%20rx%3D%222%22%2F%3E%3Ccircle%20fill%3D%22%231F1E1D%22%20cx%3D%223.667%22%20cy%3D%223.667%22%20r%3D%221%22%2F%3E%3Cpath%20stroke%3D%22%231F1E1D%22%20stroke-width%3D%221.2%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20d%3D%22m11.467%208.006-3-3.273-6.6%207.2%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E');
background-image: url("data:image/svg+xml,%3Csvg width='14' height='10' viewBox='0 0 14 10' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M1.27273 2.46667C1.27273 1.82524 1.74901 1.33333 2.32851 1.33333H7.21696C7.79643 1.33333 8.27273 1.82524 8.27273 2.46667V3.00164C8.27252 3.01142 8.27252 3.0212 8.27273 3.03102V7.53333C8.27273 8.12422 7.7815 8.66667 7.21696 8.66667H2.32851C1.76398 8.66667 1.27273 8.12422 1.27273 7.53333V2.46667ZM9.54545 3.44462V7.53333C9.54545 8.80911 8.53258 10 7.21696 10H2.32851C1.01288 10 0 8.80911 0 7.53333V2.46667C0 1.10811 1.02785 0 2.32851 0H7.21696C8.36458 0 9.29982 0.862711 9.50401 1.99898L12.0515 0.781853C12.0704 0.772787 12.0898 0.764702 12.1096 0.757631C12.5346 0.605311 12.9875 0.64676 13.3512 0.864022C13.7212 1.08499 14 1.49567 14 2.0144V7.96102C14 8.49769 13.6881 8.91382 13.3323 9.13142C12.9765 9.34902 12.4888 9.42467 12.0386 9.18742L10.8723 8.63018C10.5525 8.47738 10.4115 8.08196 10.5574 7.74698C10.7032 7.412 11.0807 7.26427 11.4004 7.41702L12.5796 7.9804C12.5897 7.98524 12.5997 7.9904 12.6096 7.99578C12.6143 7.99831 12.6204 8.00067 12.6331 7.99982C12.648 7.99889 12.669 7.9932 12.6907 7.97991C12.7101 7.96804 12.7218 7.9552 12.7273 7.94747V2.02649C12.7255 2.02524 12.7235 2.02387 12.721 2.02236C12.694 2.00627 12.6313 1.98702 12.5442 2.01191L9.54545 3.44462Z' fill='%23151618'/%3E%3C/svg%3E"); }
}
}
.qcolors{
display: inline-block;
......
......@@ -8249,7 +8249,7 @@ ms@2.1.2:
resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
ms@2.1.3, ms@^2.1.1:
ms@2.1.3, ms@^2.1.1, ms@^2.1.2:
version "2.1.3"
resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz"
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
......@@ -10280,6 +10280,13 @@ react-scripts@^3.4.1:
optionalDependencies:
fsevents "2.1.2"
react-stopwatch@^2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/react-stopwatch/-/react-stopwatch-2.0.4.tgz#b76e25bbcee0da62cfe58facd7b36c85404366bf"
integrity sha512-FBF5MS3ODWbGWi7f5wkspMuazZFBZTdUZ2Qgjct7k6tnicHTuUdY1v//MmB3PKmFDX5wrtU++DhTO3ARGVr2wQ==
dependencies:
ms "^2.1.2"
react-webcam@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/react-webcam/-/react-webcam-7.0.1.tgz#8249e1d621eb4bba7e3f52135f562439d0528df3"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment